aboutsummaryrefslogtreecommitdiff
path: root/vnext/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'vnext/src/components')
-rw-r--r--vnext/src/components/Avatar.css27
-rw-r--r--vnext/src/components/Avatar.js44
-rw-r--r--vnext/src/components/Button.css13
-rw-r--r--vnext/src/components/Button.js11
-rw-r--r--vnext/src/components/Chat.css9
-rw-r--r--vnext/src/components/Chat.js85
-rw-r--r--vnext/src/components/Contact.js21
-rw-r--r--vnext/src/components/Contacts.js49
-rw-r--r--vnext/src/components/Feeds.js171
-rw-r--r--vnext/src/components/Header.js69
-rw-r--r--vnext/src/components/Icon.js38
-rw-r--r--vnext/src/components/Input.css8
-rw-r--r--vnext/src/components/Input.js17
-rw-r--r--vnext/src/components/LoginButton.js90
-rw-r--r--vnext/src/components/Message.css210
-rw-r--r--vnext/src/components/Message.js142
-rw-r--r--vnext/src/components/MessageInput.js107
-rw-r--r--vnext/src/components/Modal.css95
-rw-r--r--vnext/src/components/Modal.js29
-rw-r--r--vnext/src/components/NavigationIcon.css4
-rw-r--r--vnext/src/components/NavigationIcon.js21
-rw-r--r--vnext/src/components/PM.js51
-rw-r--r--vnext/src/components/Post.js38
-rw-r--r--vnext/src/components/SearchBox.js26
-rw-r--r--vnext/src/components/Settings.js268
-rw-r--r--vnext/src/components/Spinner.js42
-rw-r--r--vnext/src/components/Thread.js181
-rw-r--r--vnext/src/components/Types.js15
-rw-r--r--vnext/src/components/UploadButton.js42
-rw-r--r--vnext/src/components/UserInfo.css11
-rw-r--r--vnext/src/components/UserInfo.js117
-rw-r--r--vnext/src/components/Users.js44
-rw-r--r--vnext/src/components/__tests__/Avatar.test.js15
-rw-r--r--vnext/src/components/__tests__/LoginButton.test.js21
-rw-r--r--vnext/src/components/__tests__/MessageInput-test.js95
-rw-r--r--vnext/src/components/__tests__/UserLink.test.js20
-rw-r--r--vnext/src/components/__tests__/__snapshots__/Avatar.test.js.snap41
-rw-r--r--vnext/src/components/__tests__/__snapshots__/LoginButton.test.js.snap178
-rw-r--r--vnext/src/components/__tests__/__snapshots__/UserLink.test.js.snap33
39 files changed, 0 insertions, 2498 deletions
diff --git a/vnext/src/components/Avatar.css b/vnext/src/components/Avatar.css
deleted file mode 100644
index 7bdb3115..00000000
--- a/vnext/src/components/Avatar.css
+++ /dev/null
@@ -1,27 +0,0 @@
-.Avatar {
- display: flex;
- width: 100%;
-}
-.msg-avatar {
- max-height: 48px;
- margin-right: 10px;
- max-width: 48px;
-}
-.msg-avatar img {
- max-height: 48px;
- vertical-align: top;
- max-width: 48px;
-}
-
-.info-avatar img {
- max-height: 24px;
- max-width: 24px;
- padding: 6px;
- vertical-align: middle;
-}
-
-@media screen and (min-width: 450px) {
- .Avatar {
- width: 300px;
- }
-}
diff --git a/vnext/src/components/Avatar.js b/vnext/src/components/Avatar.js
deleted file mode 100644
index dda5449f..00000000
--- a/vnext/src/components/Avatar.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import React, { memo } from 'react';
-import PropTypes from 'prop-types';
-import { Link } from 'react-router-dom';
-
-import { UserType } from './Types';
-
-import Icon from './Icon';
-
-import './Avatar.css';
-
-function Avatar({ user, style, link, children}) {
- return (
- <div className="Avatar" style={style}>
- <div className="msg-avatar">
- {
- user.uname ?
- <Link to={{ pathname: link || `/${user.uname}/` }}>
- {user.avatar ?
- <img src={user.avatar} alt={`${user.uname}`} />
- : <Icon name="ei-spinner" size="m" />}
- </Link>
- : <Icon name="ei-spinner" size="m" />
- }
- </div>
- <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
- <span>
- <Link to={{ pathname: `/${user.uname}/` }}>
- <span>{user.uname}</span>
- </Link>
- </span>
- {children}
- </div>
- </div>
- );
-}
-
-export default memo(Avatar);
-
-Avatar.propTypes = {
- user: UserType,
- link: PropTypes.string,
- style: PropTypes.object,
- children: PropTypes.node
-};
diff --git a/vnext/src/components/Button.css b/vnext/src/components/Button.css
deleted file mode 100644
index 2acb87be..00000000
--- a/vnext/src/components/Button.css
+++ /dev/null
@@ -1,13 +0,0 @@
-.Button {
- background: #fff;
- border: 1px solid #eee;
- color: #888;
- cursor: pointer;
- display: inline-block;
- margin: 5px;
- padding: 4px 10px;
-}
-.Button:hover {
- background: #f8f8f8;
- border-bottom: 1px solid #ff339a;
-}
diff --git a/vnext/src/components/Button.js b/vnext/src/components/Button.js
deleted file mode 100644
index 18cab0a7..00000000
--- a/vnext/src/components/Button.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-
-import './Button.css';
-
-function Button(props) {
- return (
- <button className="Button" {...props} />
- );
-}
-
-export default React.memo(Button);
diff --git a/vnext/src/components/Chat.css b/vnext/src/components/Chat.css
deleted file mode 100644
index 520a5c9b..00000000
--- a/vnext/src/components/Chat.css
+++ /dev/null
@@ -1,9 +0,0 @@
-.Chat_messages {
- box-sizing: border-box;
- padding: 0 20px;
- overflow-y: auto;
- height: 450px;
- display: flex;
- flex-direction: column-reverse;
- width: 100%;
-}
diff --git a/vnext/src/components/Chat.js b/vnext/src/components/Chat.js
deleted file mode 100644
index a1254a10..00000000
--- a/vnext/src/components/Chat.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import React, { useEffect, useState, useCallback } from 'react';
-import PropTypes from 'prop-types';
-import ReactRouterPropTypes from 'react-router-prop-types';
-import { UserType } from './Types';
-import moment from 'moment';
-
-import PM from './PM';
-import MessageInput from './MessageInput';
-import UserInfo from './UserInfo';
-
-import { getChat, pm } from '../api';
-
-import './Chat.css';
-
-export default function Chat(props) {
- const [chats, setChats] = useState([]);
- useEffect(() => {
- if (props.connection.addEventListener) {
- props.connection.addEventListener('msg', onMessage);
- }
- loadChat(props.match.params.user);
- console.log(props.connection);
- return () => {
- if (props.connection.removeEventListener) {
- props.connection.removeEventListener('msg', onMessage);
- }
- };
- }, [props.connection, onMessage, loadChat, props.match.params.user]);
-
- let loadChat = useCallback((uname) => {
- const { hash } = props.visitor;
- setChats([]);
- if (hash && uname) {
- getChat(uname)
- .then(response => {
- setChats(response.data);
- });
- }
- }, [props.visitor]);
-
- let onMessage = useCallback((json) => {
- const msg = JSON.parse(json.data);
- if (msg.user.uname === props.match.params.user) {
- setChats((oldChat) => {
- return [msg, ...oldChat];
- });
- }
- }, [props.match.params.user]);
-
- let onSend = (template) => {
- pm(template.to.uname, template.body)
- .then(res => {
- loadChat(props.match.params.user);
- }).catch(console.log);
- };
- const uname = props.match.params.user;
- return (
- <div className="msg-cont">
- <UserInfo user={uname} />
- {uname ? (
- <div className="chatroom">
- <ul className="Chat_messages">
- {
- chats.map((chat) =>
- <PM key={moment.utc(chat.timestamp).valueOf()} chat={chat} {...props} />
- )
- }
- </ul>
- <MessageInput data={{ mid: 0, timestamp: '0', to: { uname: uname } }} onSend={onSend}>
- Reply...
- </MessageInput>
- </div>
- ) : (
- <div className="chatroom no-selection"><p>No chat selected</p></div>
- )
- }
- </div>
- );
-}
-
-Chat.propTypes = {
- visitor: UserType.isRequired,
- match: ReactRouterPropTypes.match.isRequired,
- connection: PropTypes.object.isRequired
-};
diff --git a/vnext/src/components/Contact.js b/vnext/src/components/Contact.js
deleted file mode 100644
index 24aabe15..00000000
--- a/vnext/src/components/Contact.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { UserType } from './Types';
-
-import Avatar from './Avatar';
-
-function Contact({ user, style, ...rest }) {
- return (
- <Avatar user={user} link={`/pm/${user.uname}`} style={style}>
- {user.unreadCount && <span className="badge">{user.unreadCount}</span>}
- <div className="msg-ts">{user.lastMessageText}</div>
- </Avatar>
- );
-}
-
-export default React.memo(Contact);
-
-Contact.propTypes = {
- user: UserType,
- style: PropTypes.object
-};
diff --git a/vnext/src/components/Contacts.js b/vnext/src/components/Contacts.js
deleted file mode 100644
index 3852b26f..00000000
--- a/vnext/src/components/Contacts.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import React, { useEffect, useState } from 'react';
-
-import { getChats } from '../api';
-
-
-import Contact from './Contact.js';
-import { ChatSpinner } from './Spinner';
-
-export default function Contacts(props) {
- const [pms, setPms] = useState([]);
- useEffect(() => {
- getChats()
- .then(response => {
- setPms(response.data.pms);
- });
- }, []);
- return (
- <div className="msg-cont">
- <div style={chatListStyle}>
- {
- pms.length ? pms.map((chat) =>
- <Contact key={chat.uname} user={chat} style={chatTitleStyle} />
- ) : <><ChatSpinner /><ChatSpinner /><ChatSpinner /><ChatSpinner /><ChatSpinner /></>
- }
- </div>
- </div>
- );
-}
-
-const wrapperStyle = {
- display: 'flex',
- backgroundColor: '#fff'
-};
-
-const chatListStyle = {
- display: 'flex',
- flexDirection: 'column',
- width: '100%',
- padding: '12px'
-};
-
-const chatTitleStyle = {
- width: '100%',
- padding: '12px',
- textAlign: 'left',
- background: '#fff',
- color: '#222',
- borderBottom: '1px solid #eee'
-};
diff --git a/vnext/src/components/Feeds.js b/vnext/src/components/Feeds.js
deleted file mode 100644
index c7b857b7..00000000
--- a/vnext/src/components/Feeds.js
+++ /dev/null
@@ -1,171 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import PropTypes from 'prop-types';
-import ReactRouterPropTypes from 'react-router-prop-types';
-import { Link } from 'react-router-dom';
-import qs from 'qs';
-import moment from 'moment';
-
-import Message from './Message';
-import Spinner from './Spinner';
-
-import UserInfo from './UserInfo';
-
-import { getMessages } from '../api';
-import { UserType } from './Types';
-
-export function Discover(props) {
- let search = qs.parse(props.location.search.substring(1));
- const query = {
- baseUrl: '/api/messages',
- search: search,
- pageParam: search.search ? 'page' : 'before_mid'
- };
- return (<Feed authRequired={false} query={query} {...props} />);
-}
-
-export function Discussions(props) {
- const query = {
- baseUrl: '/api/messages/discussions',
- pageParam: 'to'
- };
- return (<Feed authRequired={false} query={query} {...props} />);
-}
-
-export function Blog(props) {
- const { user } = props.match.params;
- let search = qs.parse(props.location.search.substring(1));
- search.uname = user;
- const query = {
- baseUrl: '/api/messages',
- search: search,
- pageParam: search.search ? 'page' : 'before_mid'
- };
- return (
- <>
- <div className="msg-cont">
- <UserInfo user={user} />
- </div>
- <Feed authRequired={false} query={query} {...props} />
- </>
- );
-}
-
-export function Tag(props) {
- const { tag } = props.match.params;
- const query = {
- baseUrl: '/api/messages',
- search: {
- tag: tag
- },
- pageParam: 'before_mid'
- };
- return (<Feed authRequired={false} query={query} {...props} />);
-}
-
-export function Home(props) {
- const query = {
- baseUrl: '/api/home',
- pageParam: 'before_mid'
- };
- return (<Feed authRequired={true} query={query} {...props} />);
-}
-
-function Feed(props) {
- const [msgs, setMsgs] = useState([]);
- const [loading, setLoading] = useState(true);
- const [nextpage, setNextpage] = useState(null);
- const [error, setError] = useState(false);
-
- useEffect(() => {
- let loadMessages = (hash = '', filter = '') => {
- document.body.scrollTop = 0;
- document.documentElement.scrollTop = 0;
- setMsgs([]);
- const filterParams = qs.parse(filter);
- let params = Object.assign({}, filterParams || {}, props.query.search || {});
- let url = props.query.baseUrl;
- if (hash) {
- params.hash = hash;
- }
- if (!params.hash && props.authRequired) {
- props.history.push('/');
- }
- getMessages(url, params)
- .then(response => {
- const { data } = response;
- const { pageParam } = props.query;
- const lastMessage = data.slice(-1)[0] || {};
- const nextpage = getPageParam(pageParam, lastMessage, filterParams);
- setMsgs(data);
- setLoading(false);
- setNextpage(nextpage);
- }).catch(ex => {
- setError(true);
- });
- };
- loadMessages(props.visitor.hash, props.location.search.substring(1));
- }, [props]);
-
- let getPageParam = (pageParam, lastMessage, filterParams) => {
- const pageValue = pageParam === 'before_mid' ? lastMessage.mid : pageParam === 'page' ? (Number(filterParams.page) || 0) + 1 : moment.utc(lastMessage.updated).valueOf();
- let newFilter = { ...filterParams };
- newFilter[pageParam] = pageValue;
- return `?${qs.stringify(newFilter)}`;
- };
- const { tag } = qs.parse(location.search.substring(1) || {});
- const nodes = (
- <>
- {
- tag && (
- <p className="page">
- <Link to={{ pathname: `/tag/${tag}` }}>
- <span>← All posts with tag&nbsp;</span><b>{tag}</b>
- </Link>
- </p>
- )
- }
- {
- msgs.map(msg =>
- <Message key={msg.mid} data={msg} visitor={props.visitor} />)
- }
- {
- msgs.length >= 20 && (
- <p className="page">
- <Link to={{ pathname: props.location.pathname, search: nextpage }} rel="prev">Next →</Link>
- </p>
- )
- }
- </>
- );
- return msgs.length > 0 ? (
- <div className="msgs">{nodes}</div>
- ) : error ? <div>error</div> : loading ? <div className="msgs"><Spinner /><Spinner /><Spinner /><Spinner /></div> : <div>No more messages</div>;
-}
-
-Discover.propTypes = {
- location: ReactRouterPropTypes.location.isRequired,
- search: PropTypes.string
-};
-
-Blog.propTypes = {
- match: ReactRouterPropTypes.match.isRequired,
- location: ReactRouterPropTypes.location.isRequired,
- search: PropTypes.string
-};
-
-Tag.propTypes = {
- match: ReactRouterPropTypes.match.isRequired
-};
-
-Feed.propTypes = {
- authRequired: PropTypes.bool,
- visitor: UserType,
- history: ReactRouterPropTypes.history.isRequired,
- location: ReactRouterPropTypes.location.isRequired,
- msgs: PropTypes.array,
- query: PropTypes.shape({
- baseUrl: PropTypes.string.isRequired,
- search: PropTypes.object,
- pageParam: PropTypes.string.isRequired
- })
-};
diff --git a/vnext/src/components/Header.js b/vnext/src/components/Header.js
deleted file mode 100644
index 48f89360..00000000
--- a/vnext/src/components/Header.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, { useEffect, useCallback, useRef } from 'react';
-import ReactDOM from 'react-dom';
-import PropTypes from 'prop-types';
-
-const elClassHidden = 'header--hidden';
-
-const header = document.getElementById('header');
-header.removeChild(document.getElementById('header_wrapper'));
-
-export default function Header({ children }) {
- let dHeight = useRef(0);
- let wHeight = useRef(0);
- let wScrollCurrent = useRef(0);
- let wScrollBefore = useRef(0);
- let wScrollDiff = useRef(0);
-
- useEffect(() => {
- window.addEventListener('scroll', () => (!window.requestAnimationFrame)
- ? throttle(250, updateHeader)
- : window.requestAnimationFrame(updateHeader), false);
- }, [updateHeader]);
- let throttle = (delay, fn) => {
- var last, deferTimer;
- return function () {
- var context = this, args = arguments, now = +new Date;
- if (last && now < last + delay) {
- clearTimeout(deferTimer);
- deferTimer = setTimeout(
- function () {
- last = now;
- fn.apply(context, args);
- },
- delay);
- } else {
- last = now;
- fn.apply(context, args);
- }
- };
- };
- let updateHeader = useCallback(() => {
- dHeight.current = document.body.offsetHeight;
- wHeight.current = window.innerHeight;
- wScrollCurrent.current = window.pageYOffset;
- wScrollDiff.current = wScrollBefore.current - wScrollCurrent.current;
-
- if (wScrollCurrent.current <= 0) {
- // scrolled to the very top; element sticks to the top
- header.classList.remove(elClassHidden);
- } else if (wScrollDiff > 0 && header.classList.contains(elClassHidden)) {
- // scrolled up; element slides in
- header.classList.remove(elClassHidden);
- } else if (wScrollDiff.current < 0) {
- // scrolled down
- if (wScrollCurrent.current + wHeight.current >= dHeight.current && header.classList.contains(elClassHidden)) {
- // scrolled to the very bottom; element slides in
- header.classList.remove(elClassHidden);
- } else {
- // scrolled down; element slides out
- header.classList.add(elClassHidden);
- }
- }
- wScrollBefore.current = wScrollCurrent.current;
- }, []);
- return ReactDOM.createPortal(children, header);
-}
-
-Header.propTypes = {
- children: PropTypes.node
-};
diff --git a/vnext/src/components/Icon.js b/vnext/src/components/Icon.js
deleted file mode 100644
index faf1a704..00000000
--- a/vnext/src/components/Icon.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-const Icon = React.memo(props => {
- var size = props.size ? ' icon--' + props.size : '';
- var className = props.className ? ' ' + props.className : '';
- var klass = 'icon' + (!props.noFill ? ' icon--' + props.name : '') + size + className;
-
- var name = '#' + props.name + '-icon';
- var useTag = '<use xlink:href=' + name + ' />';
- var Icon = React.createElement('svg', { className: 'icon__cnt', dangerouslySetInnerHTML: { __html: useTag } });
- return React.createElement(
- 'div',
- { className: klass },
- wrapSpinner(Icon, klass)
- );
-});
-
-function wrapSpinner(Html, klass) {
- if (klass.indexOf('spinner') > -1) {
- return React.createElement(
- 'div',
- { className: 'icon__spinner' },
- Html
- );
- } else {
- return Html;
- }
-}
-
-export default Icon;
-
-Icon.propTypes = {
- size: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- className: PropTypes.string,
- noFill: PropTypes.bool
-};
diff --git a/vnext/src/components/Input.css b/vnext/src/components/Input.css
deleted file mode 100644
index dbe55eae..00000000
--- a/vnext/src/components/Input.css
+++ /dev/null
@@ -1,8 +0,0 @@
-.input {
- background: #FFF;
- border: 1px solid #ccc;
- outline: none !important;
- padding: 4px;
- -webkit-appearance: none;
- border-radius: 0;
-}
diff --git a/vnext/src/components/Input.js b/vnext/src/components/Input.js
deleted file mode 100644
index c74d595d..00000000
--- a/vnext/src/components/Input.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import './Input.css';
-
-function Input({ name, value, ...rest }) {
- return (
- <input className="input" name={name} value={value} {...rest} />
- );
-}
-
-Input.propTypes = {
- name: PropTypes.string.isRequired,
- value: PropTypes.string.isRequired
-};
-
-export default React.memo(Input);
diff --git a/vnext/src/components/LoginButton.js b/vnext/src/components/LoginButton.js
deleted file mode 100644
index cd26252e..00000000
--- a/vnext/src/components/LoginButton.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import React, { useState } from 'react';
-import PropTypes from 'prop-types';
-import Icon from './Icon';
-import Modal from './Modal';
-import Button from './Button';
-import Input from './Input';
-import { useFormState } from 'react-use-form-state';
-
-import { me, facebookLink, vkLink } from '../api';
-
-function LoginButton({ onAuth, title }) {
- const [open, setOpen] = useState(false);
- const [formState, { text, password }] = useFormState();
-
- let onToggle = (event) => {
- if (event) {
- event.preventDefault();
- }
- setOpen(!open);
- };
- let onSubmit = (event) => {
- event.preventDefault();
- me(formState.values.username, formState.values.password)
- .then(response => {
- onToggle();
- onAuth(response);
- }
- ).catch(ex => {
- console.log(ex);
- });
- };
- return (
- <>
- <a onClick={onToggle}>
- <Icon name="ei-user" size="s" />
- <span className="desktop">{title}</span>
- </a>
- <Modal show={open}
- onClose={onToggle}>
- <div className="dialoglogin">
- <p>Please, introduce yourself:</p>
- <div style={socialButtonsStyle}>
- <a href={facebookLink()} style={facebookButtonStyle}>
- <Icon name="ei-sc-facebook" size="s" noFill={true} />Log in
- </a>
- <a href={vkLink()} style={vkButtonStyle}>
- <Icon name="ei-sc-vk" size="s" noFill={true} />
- Log in
- </a>
- </div>
- <p>Already registered?</p>
- <form onSubmit={onSubmit}>
- <Input name="username"
- placeholder="Username..."
- value={formState.values.username} {...text('username')} /><br />
- <Input name="password"
- placeholder="Password..."
- value={formState.values.password} {...password('password')} /><br />
- <Button onClick={onSubmit}>OK</Button>
- </form>
- </div>
- </Modal>
- </>
- );
-}
-
-LoginButton.propTypes = {
- title: PropTypes.string.isRequired,
- onAuth: PropTypes.func.isRequired
-};
-
-const socialButtonsStyle = {
- display: 'flex',
- justifyContent: 'space-evenly',
- padding: '4px'
-};
-
-const facebookButtonStyle = {
- color: '#fff',
- padding: '2px 14px',
- background: '#3b5998'
-};
-
-const vkButtonStyle = {
- color: '#fff',
- padding: '2px 14px',
- background: '#4c75a3'
-};
-
-export default LoginButton;
diff --git a/vnext/src/components/Message.css b/vnext/src/components/Message.css
deleted file mode 100644
index 18d3d0d5..00000000
--- a/vnext/src/components/Message.css
+++ /dev/null
@@ -1,210 +0,0 @@
-.msg-cont .ir {
- padding: 12px;
-}
-.msg-cont .ir img {
- max-width: 100%;
- height: auto;
-}
-.msg-cont > .h,
-.msg-cont .msg-header {
- padding: 12px;
-}
-.msg-cont > .l {
- border-top: 1px solid #eee;
- display: flex;
- align-items: center;
- justify-content: space-around;
- background: #fdfdfe;
-}
-.msg-cont > .l a {
- color: #88958d;
- margin-right: 15px;
- font-size: small;
-}
-.msg-tags {
- color: #88958d;
- margin-top: 12px;
- min-height: 1px;
-}
-.badge,
-.msg-tags > a {
- color: #88958d;
- display: inline-block;
- font-size: small;
-}
-.msgthread {
- margin-bottom: 0;
-}
-.msg-cont {
- background: #FFF;
- box-shadow: 0 0 3px rgba(0, 0, 0, 0.16);
- line-height: 140%;
- margin-bottom: 12px;
-}
-.reply-new .msg-cont {
- border-right: 5px solid #0C0;
-}
-.msg-ts {
- font-size: small;
- vertical-align: top;
-}
-.msg-ts,
-.msg-ts > a {
- color: #88958d;
-}
-.msg-txt {
- margin: 0 0 12px;
- padding: 12px;
- word-wrap: break-word;
- overflow-wrap: break-word;
-}
-q:before,
-q:after {
- content: "";
-}
-q,
-blockquote {
- border-left: 3px solid #CCC;
- color: #666;
- display: block;
- margin: 10px 0 10px 10px;
- padding-left: 10px;
- word-break: break-word;
-}
-.msg-media {
- text-align: center;
-}
-.msg-links {
- color: #88958d;
- font-size: small;
- margin: 5px 0 0 0;
- padding: 12px;
-}
-.msg-comments {
- color: #88958d;
- font-size: small;
- margin-top: 10px;
- overflow: hidden;
- text-indent: 10px;
-}
-.ta-wrapper {
- border: 1px solid #DDD;
- display: flex;
- flex-grow: 1;
-}
-.msg-comment {
- display: flex;
- margin-top: 10px;
-}
-.msg-comment-hidden {
- display: none;
-}
-.msg-comment textarea {
- border: 0;
- flex-grow: 1;
- outline: none !important;
- padding: 4px;
- resize: vertical;
- vertical-align: top;
-}
-.attach-photo {
- cursor: pointer;
-}
-.attach-photo-active {
- color: green;
-}
-.msg-comment input {
- align-self: flex-start;
- background: #EEE;
- border: 1px solid #CCC;
- color: #999;
- margin: 0 0 0 6px;
- position: sticky;
- top: 70px;
- vertical-align: top;
- width: 50px;
-}
-.msg-recomms {
- color: #88958d;
- background: #fdfdfe;
- font-size: small;
- margin-bottom: 10px;
- padding: 6px;
- border-bottom: 1px solid #eee;
- overflow: hidden;
- text-indent: 10px;
-}
-.msg-summary,
-.msg-summary a {
- color: #88958d;
- font-size: small;
- padding: 12px;
- text-align: right;
-}
-#replies .msg-txt,
-#private-messages .msg-txt {
- margin: 0;
-}
-.title2 {
- background: #fff;
- margin: 20px 0;
- padding: 10px 20px;
-}
-.title2-right {
- float: right;
- line-height: 24px;
-}
-#content .title2 h2 {
- font-size: x-large;
- margin: 0;
-}
-
-.embedContainer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- justify-content: center;
- padding: 12px;
- margin: 30px -3px 15px -3px;
-}
-.embedContainer > * {
- box-sizing: border-box;
- flex-grow: 1;
- margin: 3px;
- min-width: 49%;
-}
-.embedContainer > .compact {
- flex-grow: 0;
-}
-.embedContainer .picture img {
- display: block;
-}
-.embedContainer img,
-.embedContainer video {
- max-width: 100%;
- max-height: 80vh;
-}
-.embedContainer > .audio,
-.embedContainer > .youtube {
- min-width: 90%;
-}
-.embedContainer audio {
- width: 100%;
-}
-.embedContainer iframe {
- overflow: hidden;
- resize: vertical;
- display: block;
-}
-.msg-cont .nsfw .embedContainer img,
-.msg-cont .nsfw .embedContainer video,
-.msg-cont .nsfw .embedContainer iframe,
-.msg-cont .nsfw .ir img {
- opacity: 0.1;
-}
-.msg-cont .nsfw .embedContainer img:hover,
-.msg-cont .nsfw .embedContainer video:hover,
-.msg-cont .nsfw .embedContainer iframe:hover,
-.msg-cont .nsfw .ir img:hover {
- opacity: 1;
-}
diff --git a/vnext/src/components/Message.js b/vnext/src/components/Message.js
deleted file mode 100644
index eb008bfe..00000000
--- a/vnext/src/components/Message.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import React, { useEffect, useRef } from 'react';
-import PropTypes from 'prop-types';
-import { Link } from 'react-router-dom';
-import moment from 'moment';
-
-import { UserType, MessageType } from './Types';
-import Icon from './Icon';
-import Avatar from './Avatar';
-import { UserLink } from './UserInfo';
-
-import { format, embedUrls } from '../utils/embed';
-
-import './Message.css';
-
-export default function Message({ data, visitor, children, ...rest }) {
- const isCode = (data.tags || []).indexOf('code') >= 0;
- const likesSummary = data.likes ? `${data.likes}` : 'Recommend';
- const commentsSummary = data.replies ? `${data.replies}` : 'Comment';
- const embedRef = useRef();
- const msgRef = useRef();
- useEffect(() => {
- if (msgRef.current) {
- embedUrls(msgRef.current.querySelectorAll('a'), embedRef.current);
- if (!embedRef.current.hasChildNodes()) {
- embedRef.current.style.display = 'none';
- }
- }
- }, []);
- return (
- <div className="msg-cont">
- <Recommendations forMessage={data} />
- <header className="h">
- <Avatar user={data.user}>
- <div className="msg-ts">
- <Link to={{ pathname: `/${data.user.uname}/${data.mid}`, state: { msg: data } }}>
- <time dateTime={data.timestamp}
- title={moment.utc(data.timestamp).local().format('lll')}>
- {moment.utc(data.timestamp).fromNow()}
- </time>
- </Link>
- </div>
- </Avatar>
- <TagsList user={data.user} data={data.tags || []} />
- </header>
- {
- data.body &&
- <div className="msg-txt" ref={msgRef}>
- <MessageContainer isCode={isCode} data={{ __html: format(data.body, data.mid, isCode) }} />
- </div>
- }
- {
- data.photo &&
- <div className="msg-media">
- <a href={`//i.juick.com/p/${data.mid}.${data.attach}`} data-fname={`${data.mid}.${data.attach}`}>
- <img src={`//i.juick.com/photos-512/${data.mid}.${data.attach}`} alt="" />
- </a>
- </div>
- }
- <div className="embedContainer" ref={embedRef} />
- <nav className="l">
- {visitor.uid === data.user.uid ? (
- <Link to={{ pathname: `/${data.user.uname}/${data.mid}` }} className="a-like msg-button">
- <Icon name="ei-heart" size="s" />
- <span>{likesSummary}</span>
- </Link>
- ) : visitor.uid > 0 ? (
- <Link to={{ pathname: '/post', search: `?body=!+%23${data.mid}` }} className="a-like msg-button">
- <Icon name="ei-heart" size="s" />
- <span>{likesSummary}</span>
- </Link>
- ) : (
- <a href="/login" className="a-login msg-button">
- <Icon name="ei-heart" size="s" />
- <span>{likesSummary}</span>
- </a>
- )}
- {!data.ReadOnly | (visitor.uid === data.user.uid) && (
- <>
- <Link to={{ pathname: `/${data.user.uname}/${data.mid}`, state: { msg: data } }} className="a-comment msg-button">
- <Icon name="ei-comment" size="s" />
- <span>{commentsSummary}</span>
- </Link>
- </>
- )}
- </nav>
- {children}
- </div>
- );
-}
-
-function MessageContainer({ isCode, data }) {
- return isCode ? (<pre dangerouslySetInnerHTML={data} />) : (<p dangerouslySetInnerHTML={data} />);
-}
-
-function Tags({ data, user, ...rest }) {
- return data.length > 0 && (
- <div className="msg-tags">
- {
- data.map(tag => {
- return (<Link key={tag} to={{ pathname: `/${user.uname}`, search: `?tag=${tag}` }} title={tag}>{tag}</Link>);
- }).reduce((prev, curr) => [prev, ', ', curr])
- }
- </div>
- );
-}
-
-const TagsList = React.memo(Tags);
-
-function Recommends({ forMessage, ...rest }) {
- const { likes, recommendations } = forMessage;
- return recommendations && recommendations.length > 0 && (
- <div className="msg-recomms">{'♡ by '}
- {
- recommendations.map(it => (
- <UserLink key={it.uri || it.uid} user={it} />
- )).reduce((prev, curr) => [prev, ', ', curr])
- }
- {
- likes > recommendations.length && (<span>&nbsp;and {likes - recommendations.length} others</span>)
- }
- </div>
- ) || null;
-}
-
-const Recommendations = React.memo(Recommends);
-
-Message.propTypes = {
- data: MessageType,
- visitor: UserType.isRequired,
- children: PropTypes.node
-};
-
-MessageContainer.propTypes = {
- isCode: PropTypes.bool.isRequired,
- data: PropTypes.object.isRequired
-};
-
-Tags.propTypes = {
- user: UserType.isRequired,
- data: PropTypes.array
-};
-
diff --git a/vnext/src/components/MessageInput.js b/vnext/src/components/MessageInput.js
deleted file mode 100644
index e4988d59..00000000
--- a/vnext/src/components/MessageInput.js
+++ /dev/null
@@ -1,107 +0,0 @@
-import React, { useState, useEffect, useRef } from 'react';
-import PropTypes from 'prop-types';
-
-import { useFormState } from 'react-use-form-state';
-
-import { MessageType } from './Types';
-
-import Icon from './Icon';
-import Button from './Button';
-
-import UploadButton from './UploadButton';
-
-export default function MessageInput({ text, data, rows, children, onSend }) {
- let textareaRef = useRef();
- let fileinput = useRef();
-
- let updateFocus = () => {
- const isDesktop = window.matchMedia('(min-width: 62.5rem)');
- if (isDesktop.matches) {
- textareaRef.current.focus();
- }
- };
- useEffect(() => {
- textareaRef.current.value = text || '';
- updateFocus();
- }, [text]);
-
- let handleCtrlEnter = (event) => {
- if (event.ctrlKey && (event.charCode == 10 || event.charCode == 13)) {
- onSubmit({});
- }
- };
- let textChanged = (event) => {
- const el = textareaRef.current;
- const offset = el.offsetHeight - el.clientHeight;
- const height = el.scrollHeight + offset;
- el.style.height = `${height + offset}px`;
- };
- const [attach, setAttach] = useState('');
- const [formState, { textarea }] = useFormState();
- let uploadValueChanged = (attach) => {
- setAttach(attach);
- };
- let onSubmit = (event) => {
- if (event.preventDefault) {
- event.preventDefault();
- }
- const input = fileinput.current;
- onSend({
- mid: data.mid,
- rid: data.rid || 0,
- body: formState.values.body,
- attach: attach ? input.files[0] : '',
- to: data.to || {}
- });
- setAttach('');
- formState.clearField('body');
- textareaRef.current.style.height = '';
- updateFocus();
- };
- return (
- <form className="msg-comment-target" style={{ padding: '12px' }} onSubmit={onSubmit}>
- <div style={commentStyle}>
- <textarea onChange={textChanged} onKeyPress={handleCtrlEnter}
- ref={textareaRef} style={textInputStyle} value={formState.values.body}
- rows={rows || '1'} placeholder={children} {...textarea('body')} />
- <div style={inputBarStyle}>
- <UploadButton inputRef={fileinput} value={attach} onChange={uploadValueChanged} />
- <Button onClick={onSubmit}><Icon name="ei-envelope" size="s" />Send</Button>
- </div>
- </div>
- </form>
- );
-}
-
-const commentStyle = {
- display: 'flex',
- flexDirection: 'column',
- borderTop: '1px #eee solid',
- width: '100%',
- marginTop: '10px'
-};
-
-const inputBarStyle = {
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'space-between',
- padding: '3px'
-};
-
-const textInputStyle = {
- overflow: 'hidden',
- resize: 'none',
- display: 'block',
- boxSizing: 'border-box',
- border: 0,
- outline: 'none',
- padding: '4px'
-};
-
-MessageInput.propTypes = {
- children: PropTypes.node,
- data: MessageType.isRequired,
- onSend: PropTypes.func.isRequired,
- rows: PropTypes.string,
- text: PropTypes.string
-};
diff --git a/vnext/src/components/Modal.css b/vnext/src/components/Modal.css
deleted file mode 100644
index 931b9d81..00000000
--- a/vnext/src/components/Modal.css
+++ /dev/null
@@ -1,95 +0,0 @@
-#dialogt {
- height: 100%;
- left: 0;
- position: fixed;
- top: 0;
- width: 100%;
- z-index: 10;
- display: flex;
- align-items: center;
- justify-content: center;
- background-color: rgba(0, 0, 0, 0.3);
-}
-#dialogw {
- z-index: 11;
- max-width: 96%;
- max-height: calc(100% - 100px);
- background-color: #fff;
-}
-#dialogw a {
- display: block;
-}
-#dialogw img {
- max-height: 100%;
- max-height: 90vh;
- max-width: 100%;
-}
-#dialog_header {
- width: 100%;
- height: 44px;
- display: flex;
- flex-direction: row-reverse;
- align-items: center;
-}
-.header_image {
- background: rgba(0, 0, 0, 0.28);
-}
-#dialogc {
- cursor: pointer;
- color: #ccc;
- padding-right: 6px;
-}
-.dialoglogin {
- background: #fff;
- padding: 25px;
-}
-.dialog-opened {
- overflow: hidden;
-}
-#signemail,
-#signfb,
-#signvk {
- display: block;
- line-height: 32px;
- margin: 10px 0;
- text-decoration: none;
- width: 100%;
-}
-#signvk {
- margin-bottom: 30px;
-}
-.dialoglogin form {
- margin-top: 7px;
-}
-.signinput,
-.signsubmit {
- border: 1px solid #CCC;
- margin: 3px 0;
- padding: 3px;
-}
-.signsubmit {
- width: 70px;
-}
-.dialogshare {
- background: #fff;
- min-width: 300px;
- overflow: auto;
- padding: 20px;
-}
-.dialogl {
- background: #fff;
- border: 1px solid #DDD;
- margin: 3px 0 20px;
- padding: 5px;
-}
-.dialogshare li {
- float: left;
- margin: 5px 10px 0 0;
-}
-.dialogshare a {
- display: block;
-}
-.dialogtxt {
- background: #fff;
- padding: 20px;
-}
diff --git a/vnext/src/components/Modal.js b/vnext/src/components/Modal.js
deleted file mode 100644
index 799a6f35..00000000
--- a/vnext/src/components/Modal.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import Icon from './Icon';
-
-import './Modal.css';
-
-function Modal(props) {
- return props.show ? (
- <div id="dialogt">
- <div id="dialogw">
- <div id="dialog_header">
- <div id="dialogc" onClick={props.onClose}>
- <Icon name="ei-close" size="s" />
- </div>
- </div>
- {props.children}
- </div>
- </div>
- ) : (null);
-}
-
-export default React.memo(Modal);
-
-Modal.propTypes = {
- onClose: PropTypes.func.isRequired,
- show: PropTypes.bool,
- children: PropTypes.node
-};
diff --git a/vnext/src/components/NavigationIcon.css b/vnext/src/components/NavigationIcon.css
deleted file mode 100644
index caff6195..00000000
--- a/vnext/src/components/NavigationIcon.css
+++ /dev/null
@@ -1,4 +0,0 @@
-#navicon {
- padding: 12px;
- color: #88958d;
-}
diff --git a/vnext/src/components/NavigationIcon.js b/vnext/src/components/NavigationIcon.js
deleted file mode 100644
index 0a22ac57..00000000
--- a/vnext/src/components/NavigationIcon.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import Icon from './Icon';
-
-import './NavigationIcon.css';
-
-function NavigationIcon(props) {
- return (
- <div id="navicon" className="mobile" onClick={props.onToggle}>
- <Icon name="ei-navicon" size="s"/>
- </div>
- );
-}
-
-export default React.memo(NavigationIcon);
-
-NavigationIcon.propTypes = {
- onToggle: PropTypes.func.isRequired
-};
-
diff --git a/vnext/src/components/PM.js b/vnext/src/components/PM.js
deleted file mode 100644
index a1e70ad5..00000000
--- a/vnext/src/components/PM.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from 'react';
-
-import { UserType, MessageType } from './Types';
-
-import Avatar from './Avatar';
-import { format } from '../utils/embed';
-
-function PM(props) {
- const { chat } = props;
- return (
- <li>
- <div style={chatItemStyle(props.visitor, chat)}>
- <Avatar user={chat.user} />
- <div style={bubbleStyle(props.visitor, chat)}>
- <p dangerouslySetInnerHTML={{ __html: format(chat.body) }} />
- </div>
- </div>
- </li>
- );
-}
-
-export default React.memo(PM);
-
-function bubbleStyle(me, msg) {
- const isMe = me.uid === msg.user.uid;
- const color = isMe ? '#fff' : '#222';
- const background = isMe ? '#ec4b98' : '#eee';
- return {
- background: background,
- color: color,
- padding: '12px'
- };
-}
-
-function chatItemStyle(me, msg) {
- const isMe = me.uid === msg.user.uid;
- const alignment = isMe ? 'flex-end' : 'flex-start';
- return {
- padding: '3px 6px',
- listStyle: 'none',
- margin: '10px 0',
- display: 'flex',
- flexDirection: 'column',
- alignItems: alignment
- };
-}
-
-PM.propTypes = {
- chat: MessageType.isRequired,
- visitor: UserType.isRequired
-};
diff --git a/vnext/src/components/Post.js b/vnext/src/components/Post.js
deleted file mode 100644
index 3dc23613..00000000
--- a/vnext/src/components/Post.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React, { memo } from 'react';
-
-import ReactRouterPropTypes from 'react-router-prop-types';
-import { UserType } from './Types';
-
-import qs from 'qs';
-
-import MessageInput from './MessageInput';
-
-import { post } from '../api';
-
-function PostComponent(props) {
- let params = qs.parse(window.location.search.substring(1));
- let postMessage = (template) => {
- const { attach, body } = template;
- post(body, attach)
- .then(response => {
- if (response.status === 200) {
- const msg = response.data.newMessage;
- this.props.history.push(`/${this.props.visitor.uname}/${msg.mid}`);
- }
- }).catch(console.log);
- };
- return (
- <div className="msg-cont">
- <MessageInput rows="7" text={params.body || ''} data={{ mid: 0, timestamp: '0' }} onSend={postMessage}>
- *weather It is very cold today!
- </MessageInput>
- </div>
- );
-}
-
-export default memo(PostComponent);
-
-PostComponent.propTypes = {
- history: ReactRouterPropTypes.history.isRequired,
- visitor: UserType
-};
diff --git a/vnext/src/components/SearchBox.js b/vnext/src/components/SearchBox.js
deleted file mode 100644
index a79100cd..00000000
--- a/vnext/src/components/SearchBox.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import ReactRouterPropTypes from 'react-router-prop-types';
-import { withRouter } from 'react-router-dom';
-import { useFormState } from 'react-use-form-state';
-
-function SearchBox({ onSearch, history, pathname }) {
- let onSubmit = (event) => {
- event.preventDefault();
- onSearch(history, pathname, formState.values.search);
- };
- const [formState, { text }] = useFormState();
- return (
- <form onSubmit={onSubmit}>
- <input name="search" className="text"
- placeholder="Search..." value={ formState.values.search } {...text('search')} />
- </form>
- );
-}
-
-SearchBox.propTypes = {
- pathname: PropTypes.string.isRequired,
- onSearch: PropTypes.func.isRequired,
- history: ReactRouterPropTypes.history.isRequired
-};
-export default withRouter(SearchBox);
diff --git a/vnext/src/components/Settings.js b/vnext/src/components/Settings.js
deleted file mode 100644
index cf6926f8..00000000
--- a/vnext/src/components/Settings.js
+++ /dev/null
@@ -1,268 +0,0 @@
-import React, { useState, useEffect, useRef } from 'react';
-import PropTypes from 'prop-types';
-import ReactRouterPropTypes from 'react-router-prop-types';
-
-import { me, updateAvatar } from '../api';
-
-import { UserType } from './Types';
-
-import Button from './Button';
-import Icon from './Icon';
-import UploadButton from './UploadButton';
-import Avatar from './Avatar';
-
-function ChangeAvatarForm({ visitor }) {
- const [avatar, setAvatar] = useState('');
- const [preview, setPreview] = useState();
- const avatarInput = useRef();
- let avatarChanged = (newAvatar) => {
- setAvatar(newAvatar);
- setPreview('');
- if (newAvatar) {
- let reader = new FileReader();
- reader.onloadend = (preview) => {
- setPreview(preview.target.result);
- };
- reader.readAsDataURL(avatarInput.current.files[0]);
- }
- };
- let previewUser = { ...visitor, uname: '<preview>' };
- if (preview) {
- previewUser = { ...visitor, avatar: preview, uname: '<preview>' };
- }
- let onSubmitAvatar = (event) => {
- if (event.preventDefault) {
- event.preventDefault();
- }
- updateAvatar(avatarInput.current.files[0]).then(() => {
- avatarChanged('');
- me().then(visitor => {
- this.props.onChange(visitor);
- });
- });
- };
- return (
- <form>
- <small>Recommendations: PNG, 96x96, &lt;50Kb. Also, JPG and GIF supported.</small>
- <UploadButton inputRef={avatarInput}
- value={avatar} onChange={avatarChanged} />
- <Avatar user={visitor} />
- <Avatar user={previewUser} />
- <Button onClick={onSubmitAvatar}>Update</Button>
- </form>
- );
-}
-
-ChangeAvatarForm.propTypes = {
- visitor: UserType.isRequired
-};
-
-export default class Settings extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- settings: {
- },
- me: {}
- };
- }
- componentDidMount() {
- me().then(visitor => {
- this.setState({
- me: visitor
- });
- });
- }
-
- passwordChanged = (event) => {
- let newState = update(this.state, {
- settings: { password: { $set: event.target.value } }
- });
- this.setState(newState);
- }
- onSubmitPassword = (event) => {
- if (event.preventDefault) {
- event.preventDefault();
- }
- console.log('password update');
- }
- emailChanged = (event) => {
- let newState = update(this.state, {
- me: { activeEmail: { $set: event.target.value } }
- });
- this.setState(newState);
- console.log('email update');
- }
- disableTelegram = () => {
- console.log('telegram disable');
- }
- disableFacebook = (event) => {
- if (event.preventDefault) {
- event.preventDefault();
- }
- console.log('facebook disable');
- }
- enableFacebook = (event) => {
- if (event.preventDefault) {
- event.preventDefault();
- }
- console.log('facebook enable');
- }
- disableTwitter = () => {
- console.log('twitter disable');
- }
-
- render() {
- const { me, settings } = this.state;
- return (
- <div className="msg-cont">
- <fieldset>
- <legend><Icon name="ei-user" size="m" />Changing your avatar</legend>
- <ChangeAvatarForm visitor={me} />
- </fieldset>
- <fieldset>
- <legend><Icon name="ei-unlock" size="m" />Changing your password</legend>
- <form>
- <p>Change password: <input type="password" name="password" size="8" onChange={this.passwordChanged} />
- <Button onClick={this.onSubmitPassword}>Update</Button><br />
- <i>(max. length - 16 symbols)</i></p>
- </form>
- </fieldset>
- <fieldset>
- <legend><Icon name="ei-sc-telegram" size="m" />Telegram</legend>
- {me.telegramName ? (
- <form>
- <div>Telegram: <b> {me.telegramName} </b>&mdash;
- <Button onClick={this.disableTelegram}>Disable</Button>
- </div>
- </form>
- ) : (
- <p>To connect Telegram account: send any text message to <a href="https://telegram.me/Juick_bot">@Juick_bot</a>
- </p>
- )}
- </fieldset>
- {me.jids && (
- <form>
- <fieldset>
- <legend>XMPP accounts
- </legend>
- <p>Your accounts:</p>
- <p>
- {
- me.jids.map(jid =>
- <React.Fragment key={jid}>
- <label><input type="radio" name="delete" value={jid} />{jid}</label><br />
- </React.Fragment>
- )
- }
- </p>
- {
- me.jids && me.jids.length > 1 &&
- <p><Button onClick={this.deleteJid}>Delete</Button></p>
- }
- <p>To add new jabber account: send any text message to <a href="xmpp:juick@juick.com?message;body=login">juick@juick.com</a>
- </p>
- </fieldset>
- </form>
- )}
- <fieldset>
- <legend><Icon name="ei-envelope" size="m" />E-mail</legend>
- <form>
- <p>Add account:<br />
- <input type="text" name="account" />
- <input type="hidden" name="page" value="email-add" />
- <Button onClick={this.addEmail}>Add</Button>
- </p>
- </form>
- <form>
- <p>Your accounts:</p>
- <p>
- {
- me.emails ? me.emails.map(email =>
- <React.Fragment key={email}>
- <label>
- <input type="radio" name="account" value={email} />{email}
- </label>
- <br />
- </React.Fragment>
- ) : '-'
- }
- </p>
- {
- me.emails && me.emails.length > 1 &&
- <Button onClick={this.deleteEmail}>Delete</Button>
- }
- </form>
- {
- me.emails &&
- <>
- {/** email_off **/}
- <form>
- You can receive notifications to email:<br />
- Sent to <select name="account" value={me.activeEmail || 'Disabled'} onChange={this.emailChanged}>
- <option value="">Disabled</option>
- {
- me.emails.map(email =>
- <option key={email} value={email}>
- {email}
- </option>
- )
- }
- </select>
- </form>
- {/** /email_off **/}
- <p>&nbsp;</p>
- <p>You can post to Juick via e-mail. Send your <u>plain text</u> messages to <span><a href="mailto:juick@juick.com">juick@juick.com</a></span>. You can attach one photo or video file.</p>
- </>
- }
- </fieldset>
- <fieldset>
- <legend><Icon name="ei-sc-facebook" size="m" />Facebook</legend>
- {me.facebookStatus && me.facebookStatus.connected ? (
- me.facebookStatus.crosspostEnabled ?
- <form>
- <div>
- Facebook: <b>Enabled</b> &mdash;
- <Button onClick={this.disableFacebook}>Disable</Button>
- </div>
- </form>
- :
- <form>
- <div>
- Facebook: <b>Disabled</b> &mdash;
- <Button onClick={this.enableFacebook}>Enable</Button>
- </div>
- </form>
- ) : (
- <p>Cross-posting to Facebook:
- <a href="/_fblogin">
- <img src="//static.juick.com/facebook-connect.png" alt="Connect to Facebook" />
- </a>
- </p>
- )}
- </fieldset>
- <fieldset>
- <legend><Icon name="ei-sc-twitter" size="m" />Twitter</legend>
- {me.twitterName ?
- <form action="/settings" method="post">
- <div>Twitter: <b>{me.twitterName}</b> &mdash;
- <input type="hidden" name="page" value="twitter-del" />
- <Button onClick={this.disableTwitter}>Disable</Button>
- </div>
- </form>
- :
- <p>Cross-posting to Twitter: <a href="/_twitter"><img src="//static.juick.com/twitter-connect.png"
- alt="Connect to Twitter" /></a></p>
- }
- </fieldset>
-
- </div>
- );
- }
-}
-
-Settings.propTypes = {
- visitor: UserType.isRequired,
- onChange: PropTypes.func.isRequired
-};
-
diff --git a/vnext/src/components/Spinner.js b/vnext/src/components/Spinner.js
deleted file mode 100644
index e866369f..00000000
--- a/vnext/src/components/Spinner.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import ContentLoader from 'react-content-loader';
-
-function Spinner(props) {
- return (
- <div className="msg-cont">
- <div className="msg-txt">
- <ContentLoader
- speed={2}
- primaryColor="#f8f8f8"
- secondaryColor="#ecebeb"
- {...props}>
- <rect x="56" y="6" rx="0" ry="0" width="117" height="6.4" />
- <rect x="56" y="20" rx="0" ry="0" width="85" height="6.4" />
- <rect x="0" y="60" rx="0" ry="0" width="270" height="6.4" />
- <rect x="0" y="78" rx="0" ry="0" width="270" height="6.4" />
- <rect x="0" y="96" rx="0" ry="0" width="201" height="6.4" />
- <rect x="0" y="0" rx="0" ry="0" width="48" height="48" />
- <rect x="0" y="120" rx="0" ry="0" width="270" height="1" />
- </ContentLoader>
- </div>
- </div>
- );
-}
-
-export default React.memo(Spinner);
-
-export function ChatSpinner(props) {
- return (
- <ContentLoader
- speed={2}
- primaryColor="#f8f8f8"
- secondaryColor="#ecebeb"
- height="60px"
- width="120px"
- {...props}>
- <rect x="56" y="6" rx="0" ry="0" width="117" height="6.4" />
- <rect x="56" y="20" rx="0" ry="0" width="85" height="6.4" />
- <rect x="0" y="0" rx="0" ry="0" width="48" height="48" />
- </ContentLoader>
- );
-}
diff --git a/vnext/src/components/Thread.js b/vnext/src/components/Thread.js
deleted file mode 100644
index e7ccb032..00000000
--- a/vnext/src/components/Thread.js
+++ /dev/null
@@ -1,181 +0,0 @@
-import React, { useEffect, useState, useRef, useCallback } from 'react';
-import PropTypes from 'prop-types';
-
-import ReactRouterPropTypes from 'react-router-prop-types';
-import { UserType, MessageType } from './Types';
-
-import Message from './Message';
-import MessageInput from './MessageInput';
-import Spinner from './Spinner';
-import Avatar from './Avatar';
-import Button from './Button';
-
-import { format, embedUrls } from '../utils/embed';
-
-import { getMessages, comment, markReadTracker } from '../api';
-
-function Comment({ msg, visitor, active, setActive, postComment }) {
- const embedRef = useRef();
- const msgRef = useRef();
- useEffect(() => {
- if (msgRef.current) {
- embedUrls(msgRef.current.querySelectorAll('a'), embedRef.current);
- if (!embedRef.current.hasChildNodes()) {
- embedRef.current.style.display = 'none';
- }
- }
- }, []);
- return (
- <div className="msg-cont">
- <div className="msg-header">
- <Avatar user={msg.user}>
- <div className="msg-ts">
- {msg.replyto > 0 &&
- (
- <a href={`#${msg.replyto}`} className="info-avatar"><img src={msg.to.avatar} /> {msg.to.uname}&nbsp;</a>
- )}
- </div>
- </Avatar>
- </div>
- {
- msg.html ? <div className="msg-txt" dangerouslySetInnerHTML={{ __html: msg.body }} ref={msgRef} />
- :
- <div className="msg-txt" ref={msgRef}>
- <p dangerouslySetInnerHTML={{ __html: format(msg.body, msg.mid, (msg.tags || []).indexOf('code') >= 0) }} />
- </div>
- }
- {
- msg.photo &&
- <div className="msg-media">
- <a href={`//i.juick.com/p/${msg.mid}-${msg.rid}.${msg.attach}`} data-fname={`${msg.mid}-${msg.rid}.${msg.attach}`}>
- <img src={`//i.juick.com/p/${msg.mid}-${msg.rid}.${msg.attach}`} alt="" />
- </a>
- </div>
- }
- <div className="embedContainer" ref={embedRef} />
- <div className="msg-links">
- {
- visitor.uid > 0 ? (
- <>
- {active === msg.rid || <span style={linkStyle} onClick={() => setActive(msg.rid)}>Reply</span>}
- {active === msg.rid && <MessageInput data={msg} onSend={postComment}>Write a comment...</MessageInput>}
- </>
- ) : (
- <>
- <span>&nbsp;&middot;&nbsp;</span>{active === msg.rid || <Button>Reply</Button>}
- </>
- )
- }
- </div>
- </div>
- );
-}
-
-Comment.propTypes = {
- msg: MessageType.isRequired,
- visitor: UserType.isRequired,
- active: PropTypes.number.isRequired,
- setActive: PropTypes.func.isRequired,
- postComment: PropTypes.func.isRequired
-};
-
-export default function Thread(props) {
- const [message, setMessage] = useState((props.location.state || {}).msg || {});
- const [replies, setReplies] = useState([]);
- const [loading, setLoading] = useState(false);
- const [active, setActive] = useState(0);
- useEffect(() => {
- setActive(0);
- loadReplies();
- }, [loadReplies]);
- useEffect(() => {
- if (props.connection.addEventListener && message.mid) {
- props.connection.addEventListener('msg', onReply);
- }
- return () => {
- if (props.connection.removeEventListener && message.mid) {
- props.connection.removeEventListener('msg', onReply);
- }
- };
- }, [props.connection, message.mid, onReply]);
-
- let loadReplies = useCallback(() => {
- document.body.scrollTop = 0;
- document.documentElement.scrollTop = 0;
-
- setReplies([]);
- setLoading(true);
- const { mid } = props.match.params;
- let params = {
- mid: mid
- };
- if (props.visitor && props.visitor.hash) {
- params.hash = props.visitor.hash;
- }
- getMessages('/api/thread', params)
- .then(response => {
- setMessage(response.data.shift());
- setReplies(response.data);
- setLoading(false);
- setActive(0);
- }
- ).catch(ex => {
- console.log(ex);
- });
- }, [props.visitor, props.match.params]);
- let onReply = useCallback((json) => {
- const msg = JSON.parse(json.data);
- if (msg.mid == message.mid) {
- setReplies(oldReplies => {
- return [...oldReplies, msg];
- });
- }
- }, [message]);
- let postComment = (template) => {
- const { mid, rid, body, attach } = template;
- comment(mid, rid, body, attach).then(res => {
- loadReplies();
- })
- .catch(console.log);
- };
-
- const loaders = Math.min(message.replies || 0, 10);
- return (
- <>
- {
- message.mid ? (
- <Message data={message} visitor={props.visitor}>
- {active === (message.rid || 0) && <MessageInput data={message} onSend={postComment}>Write a comment...</MessageInput>}
- </Message>
- ) : (
- <Spinner />
- )
- }
- <ul id="replies">
- {
- !loading ? replies.map((msg) => (
- <li id={msg.rid} key={msg.rid} className="msg">
- <Comment msg={msg} visitor={props.visitor} active={active} setActive={setActive} postComment={postComment} />
- </li>
- )) : (
- <>
- {Array(loaders).fill().map((it, i) => <Spinner key={i} />)}
- </>
- )
- }
- </ul>
- </>
- );
-}
-
-const linkStyle = {
- cursor: 'pointer'
-};
-
-Thread.propTypes = {
- location: ReactRouterPropTypes.location,
- history: ReactRouterPropTypes.history,
- match: ReactRouterPropTypes.match,
- visitor: UserType.isRequired,
- connection: PropTypes.object.isRequired
-};
diff --git a/vnext/src/components/Types.js b/vnext/src/components/Types.js
deleted file mode 100644
index 9bf7b513..00000000
--- a/vnext/src/components/Types.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import PropTypes from 'prop-types';
-
-export const UserType = PropTypes.shape({
- uid: PropTypes.number.isRequired,
- uname: PropTypes.string,
- avatar: PropTypes.string,
- uri: PropTypes.string
-});
-
-export const MessageType = PropTypes.shape({
- mid: PropTypes.number,
- user: UserType,
- timestamp: PropTypes.string.isRequired,
- body: PropTypes.string
-});
diff --git a/vnext/src/components/UploadButton.js b/vnext/src/components/UploadButton.js
deleted file mode 100644
index 73cbbfcf..00000000
--- a/vnext/src/components/UploadButton.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import Icon from './Icon';
-
-export default function UploadButton(props) {
- let openfile = () => {
- const input = props.inputRef.current;
- if (props.value) {
- props.onChange('');
- } else {
- input.click();
- }
- };
- let attachmentChanged = (event) => {
- props.onChange(event.target.value);
- };
- return (
- <div style={props.value ? activeStyle : inactiveStyle}
- onClick={openfile}>
- <Icon name="ei-camera" size="s" />
- <input type="file" accept="image/jpeg,image/png" onClick={e => e.stopPropagation()}
- style={{ display: 'none' }} ref={props.inputRef} value={props.value}
- onChange={attachmentChanged} />
- </div>
- );
-}
-
-UploadButton.propTypes = {
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
- inputRef: PropTypes.shape({ current: PropTypes.instanceOf(Element) })
-};
-
-const inactiveStyle = {
- cursor: 'pointer',
- color: '#888'
-};
-const activeStyle = {
- cursor: 'pointer',
- color: 'green'
-};
diff --git a/vnext/src/components/UserInfo.css b/vnext/src/components/UserInfo.css
deleted file mode 100644
index 92cfdb6c..00000000
--- a/vnext/src/components/UserInfo.css
+++ /dev/null
@@ -1,11 +0,0 @@
-.userinfo {
- padding: 40px;
- background-color: #fdfdfe;
- margin: 12px;
-}
-.info-avatar img {
- max-height: 24px;
- max-width: 24px;
- padding: 6px;
- vertical-align: middle;
-}
diff --git a/vnext/src/components/UserInfo.js b/vnext/src/components/UserInfo.js
deleted file mode 100644
index 7d84488e..00000000
--- a/vnext/src/components/UserInfo.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import PropTypes from 'prop-types';
-import { Link } from 'react-router-dom';
-
-import { UserType } from './Types';
-
-import { info, fetchUserUri } from '../api';
-
-import Avatar from './Avatar';
-import Icon from './Icon';
-import SearchBox from './SearchBox';
-
-import './UserInfo.css';
-
-let isMounted;
-
-export default function UserInfo(props) {
- const [user, setUser] = useState({ uname: props.user, uid: 0 });
- const { onUpdate } = props;
- useEffect(() => {
- isMounted = true;
- if (!user.avatar) {
- info(user.uname).then(response => {
- if (isMounted) {
- setUser(response.data);
- onUpdate && onUpdate(response.data);
- }
- });
- }
- return () => {
- isMounted = false;
- };
- }, [onUpdate, user, user.avatar]);
- return (
- <>
- <div className="userinfo">
- <Avatar user={user}>
- <div className="msg-ts">Was online recently</div>
- </Avatar>
- </div>
- <UserSummary user={user} />
- <div className="l">
- {
- user.uid > 0 &&
- <>
- <Link to={`/pm/${user.uname}`}>
- <Icon name="ei-envelope" size="s" />
- <span className="desktop">PM</span>
- </Link>
- <Link to={`/${user.uname}/?show=recomm`} rel="nofollow">
- <Icon name="ei-heart" size="s" />
- <span className="desktop">Recommendations</span>
- </Link>
- <Link to={`/${user.uname}/?media=1`} rel="nofollow">
- <Icon name="ei-camera" size="s" />
- <span className="desktop">Photos</span>
- </Link>
- </>
- }
- </div>
- {props.children}
- </>
- );
-}
-
-function Summary({ user }) {
- const readUrl = `/${user.uname}/friends`;
- const readersUrl = `/${user.uname}/readers`;
- const blUrl = `/${user.uname}/bl`;
- let read = user.read && <Link key={readUrl} to={readUrl}>I read: {user.read.length}</Link>;
- let readers = user.readers && <Link key={readersUrl} to={readersUrl}>My readers: {user.readers.length}</Link>;
- let mybl = user.statsMyBL && <Link key={blUrl} to={blUrl}>My blacklist: {user.statsMyBL}</Link>;
- let presentItems = [read, readers, mybl].filter(Boolean);
- return (
- <div className="msg-summary">
- {presentItems.length > 0 && presentItems.reduce((prev, curr) => [prev, ' ', curr])}
- </div>
- );
-}
-
-Summary.propTypes = {
- user: UserType.isRequired
-};
-
-const UserSummary = React.memo(Summary);
-
-export function UserLink(props) {
- const [user, setUser] = useState(props.user);
- useEffect(() => {
- isMounted = true;
- if (!user.uid && user.uri) {
- fetchUserUri(user.uri).then(response => {
- if (isMounted) {
- setUser({ ...response.data, uid: 66666666 });
- }
- });
- }
- return () => {
- isMounted = false;
- };
- }, [user.uid, user.uri]);
- return (
- user.uid ?
- <Link key={user.uid} to={`/${user.uname}/`} className="info-avatar"><img src={user.avatar} />{user.uname}</Link>
- : <a href={user.uri} className="info-avatar"><img src={user.avatar} />{user.uname}</a>
- );
-}
-
-UserInfo.propTypes = {
- user: PropTypes.string.isRequired,
- onUpdate: PropTypes.func,
- children: PropTypes.node
-};
-
-UserLink.propTypes = {
- user: UserType.isRequired
-};
diff --git a/vnext/src/components/Users.js b/vnext/src/components/Users.js
deleted file mode 100644
index a10bba7f..00000000
--- a/vnext/src/components/Users.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import React, { useState } from 'react';
-import PropTypes from 'prop-types';
-import ReactRouterPropTypes from 'react-router-prop-types';
-
-import UserInfo from './UserInfo';
-import Avatar from './Avatar';
-
-export function Friends({ match }) {
- return <Users user={match.params.user} prop='read' />;
-}
-
-export function Readers({ match }) {
- return <Users user={match.params.user} prop='readers' />;
-}
-
-function Users(props) {
- const [user, setUser] = useState({ uid: 0, uname: props.user });
- return (
- <UserInfo user={user.uname} onUpdate={setUser}>
- <div style={{ display: 'flex', flexWrap: 'wrap', flexDirection: 'row' }}>
- {
- user[props.prop] &&
- user[props.prop].map(user =>
- <Avatar key={user.uid} user={user} />
- )
- }
- </div>
- </UserInfo>
- );
-}
-
-
-Friends.propTypes = {
- match: ReactRouterPropTypes.match.isRequired
-};
-
-Readers.propTypes = {
- match: ReactRouterPropTypes.match.isRequired
-};
-
-Users.propTypes = {
- user: PropTypes.string.isRequired,
- prop: PropTypes.string.isRequired
-};
diff --git a/vnext/src/components/__tests__/Avatar.test.js b/vnext/src/components/__tests__/Avatar.test.js
deleted file mode 100644
index e7221871..00000000
--- a/vnext/src/components/__tests__/Avatar.test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import { MemoryRouter } from 'react-router-dom';
-
-import Avatar from '../Avatar';
-import renderer from 'react-test-renderer';
-
-test('Avatar renders correctly', () => {
- const component = renderer.create(
- <MemoryRouter>
- <Avatar user={{ uid: 1, uname: 'ugnich', avatar: 'https://juick.com/i/a/1-deadbeef.png' }} />
- </MemoryRouter>
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/vnext/src/components/__tests__/LoginButton.test.js b/vnext/src/components/__tests__/LoginButton.test.js
deleted file mode 100644
index da80abb0..00000000
--- a/vnext/src/components/__tests__/LoginButton.test.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-
-import LoginButton from '../LoginButton';
-import { create, act } from 'react-test-renderer';
-
-test('Login button and form are renders correctly', () => {
- var button = null;
- act(() => {
- button = create(
- <LoginButton title="Log in" onAuth={() => { }} />
- );
- });
- let link = button.toJSON();
- expect(link).toMatchSnapshot();
-
- act(() => {
- button.root.findByType('a').props.onClick();
- });
- let modal = button.toJSON();
- expect(modal).toMatchSnapshot();
-});
diff --git a/vnext/src/components/__tests__/MessageInput-test.js b/vnext/src/components/__tests__/MessageInput-test.js
deleted file mode 100644
index 7ac69ed0..00000000
--- a/vnext/src/components/__tests__/MessageInput-test.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import React from 'react';
-import { create, act } from 'react-test-renderer';
-
-import MessageInput from '../MessageInput';
-
-const testMessage = {
- mid: 1,
- rid: 0,
- body: 'test message',
- timestamp: new Date().toISOString(),
- attach: '',
- to: {}
-};
-
-window.matchMedia = window.matchMedia || function () {
- return {
- matches: true,
- addListener: function () { },
- removeListener: function () { }
- };
-};
-
-it('Gives immediate focus on to textarea on load', () => {
- let focused = false;
- act(() => {
- create(<MessageInput data={testMessage} onSend={() => { }} />, {
- createNodeMock: (element) => {
- if (element.type === 'textarea') {
- // mock a focus function
- return {
- focus: () => {
- focused = true;
- },
- style: {}
- };
- }
- return null;
- }
- });
- });
- expect(focused).toEqual(true, 'textarea was not focused');
-});
-
-
-it('Submits on ctrl-enter', () => {
- const onSend = jest.fn();
- var messageInput = null;
- act(() => {
- messageInput = create(<MessageInput data={testMessage} onSend={onSend} />, {
- createNodeMock: (element) => {
- if (element.type === 'textarea') {
- return {
- focus: () => { },
- style: {}
- };
- }
- return null;
- }
- });
- });
- let textarea = messageInput.root.findByType('textarea');
- act(() => {
-
- textarea.props.onKeyPress({
- charCode: 13,
- which: 13,
- keyCode: 13,
- ctrlKey: false
- });
- });
- expect(onSend).toHaveBeenCalledTimes(0);
- act(() => {
- textarea.props.onKeyPress({
- charCode: 13,
- which: 13,
- keyCode: 13,
- ctrlKey: true
- });
- });
- expect(onSend).toHaveBeenCalledTimes(1);
- expect(textarea.props.value).toEqual('');
- act(() => {
- textarea.props.onChange({
- target: {
- value: ' ',
- validity: {}
- }
- });
- });
- expect(textarea.props.value).toEqual(' ');
- act(() => {
- messageInput.root.findByType('form').props.onSubmit({ event: {} });
- });
- expect(textarea.props.value).toEqual('', 'Value should be cleared after submit');
-});
diff --git a/vnext/src/components/__tests__/UserLink.test.js b/vnext/src/components/__tests__/UserLink.test.js
deleted file mode 100644
index a75344b0..00000000
--- a/vnext/src/components/__tests__/UserLink.test.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import { MemoryRouter, Switch, Route } from 'react-router-dom';
-
-import { UserLink } from '../UserInfo';
-import renderer from 'react-test-renderer';
-
-test('UserLink renders correctly', async () => {
- const component = renderer.create(
- <MemoryRouter>
- <>
- <UserLink user={{ uid: 1, uname: 'ugnich', avatar: 'https://juick.com/i/a/1-deadbeef.png' }} />
- <UserLink user={{ uid: 1, uname: 'ugnich', avatar: 'https://juick.com/i/a/1-deadbeef.png', uri: '' }} />
- <UserLink user={{ uid: 0, uname: '', uri: 'https://example.com/u/test' }} />
- </>
- </MemoryRouter>
- );
- await Promise.resolve();
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/vnext/src/components/__tests__/__snapshots__/Avatar.test.js.snap b/vnext/src/components/__tests__/__snapshots__/Avatar.test.js.snap
deleted file mode 100644
index 47614f5a..00000000
--- a/vnext/src/components/__tests__/__snapshots__/Avatar.test.js.snap
+++ /dev/null
@@ -1,41 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Avatar renders correctly 1`] = `
-<div
- className="Avatar"
->
- <div
- className="msg-avatar"
- >
- <a
- href="/ugnich/"
- onClick={[Function]}
- >
- <img
- alt="ugnich"
- src="https://juick.com/i/a/1-deadbeef.png"
- />
- </a>
- </div>
- <div
- style={
- Object {
- "display": "flex",
- "flexDirection": "column",
- "justifyContent": "center",
- }
- }
- >
- <span>
- <a
- href="/ugnich/"
- onClick={[Function]}
- >
- <span>
- ugnich
- </span>
- </a>
- </span>
- </div>
-</div>
-`;
diff --git a/vnext/src/components/__tests__/__snapshots__/LoginButton.test.js.snap b/vnext/src/components/__tests__/__snapshots__/LoginButton.test.js.snap
deleted file mode 100644
index cd08b1b4..00000000
--- a/vnext/src/components/__tests__/__snapshots__/LoginButton.test.js.snap
+++ /dev/null
@@ -1,178 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Login button and form are renders correctly 1`] = `
-<a
- onClick={[Function]}
->
- <div
- className="icon icon--ei-user icon--s"
- >
- <svg
- className="icon__cnt"
- dangerouslySetInnerHTML={
- Object {
- "__html": "<use xlink:href=#ei-user-icon />",
- }
- }
- />
- </div>
- <span
- className="desktop"
- >
- Log in
- </span>
-</a>
-`;
-
-exports[`Login button and form are renders correctly 2`] = `
-Array [
- <a
- onClick={[Function]}
- >
- <div
- className="icon icon--ei-user icon--s"
- >
- <svg
- className="icon__cnt"
- dangerouslySetInnerHTML={
- Object {
- "__html": "<use xlink:href=#ei-user-icon />",
- }
- }
- />
- </div>
- <span
- className="desktop"
- >
- Log in
- </span>
- </a>,
- <div
- id="dialogt"
- >
- <div
- id="dialogw"
- >
- <div
- id="dialog_header"
- >
- <div
- id="dialogc"
- onClick={[Function]}
- >
- <div
- className="icon icon--ei-close icon--s"
- >
- <svg
- className="icon__cnt"
- dangerouslySetInnerHTML={
- Object {
- "__html": "<use xlink:href=#ei-close-icon />",
- }
- }
- />
- </div>
- </div>
- </div>
- <div
- className="dialoglogin"
- >
- <p>
- Please, introduce yourself:
- </p>
- <div
- style={
- Object {
- "display": "flex",
- "justifyContent": "space-evenly",
- "padding": "4px",
- }
- }
- >
- <a
- href="https://juick.com/api/_fblogin?state=http://localhost/"
- style={
- Object {
- "background": "#3b5998",
- "color": "#fff",
- "padding": "2px 14px",
- }
- }
- >
- <div
- className="icon icon--s"
- >
- <svg
- className="icon__cnt"
- dangerouslySetInnerHTML={
- Object {
- "__html": "<use xlink:href=#ei-sc-facebook-icon />",
- }
- }
- />
- </div>
- Log in
- </a>
- <a
- href="https://juick.com/api/_vklogin?state=http://localhost/"
- style={
- Object {
- "background": "#4c75a3",
- "color": "#fff",
- "padding": "2px 14px",
- }
- }
- >
- <div
- className="icon icon--s"
- >
- <svg
- className="icon__cnt"
- dangerouslySetInnerHTML={
- Object {
- "__html": "<use xlink:href=#ei-sc-vk-icon />",
- }
- }
- />
- </div>
- Log in
- </a>
- </div>
- <p>
- Already registered?
- </p>
- <form
- onSubmit={[Function]}
- >
- <input
- className="input"
- name="username"
- onBlur={[Function]}
- onChange={[Function]}
- placeholder="Username..."
- type="text"
- value=""
- />
- <br />
- <input
- className="input"
- name="password"
- onBlur={[Function]}
- onChange={[Function]}
- placeholder="Password..."
- type="password"
- value=""
- />
- <br />
- <button
- className="Button"
- onClick={[Function]}
- >
- OK
- </button>
- </form>
- </div>
- </div>
- </div>,
-]
-`;
diff --git a/vnext/src/components/__tests__/__snapshots__/UserLink.test.js.snap b/vnext/src/components/__tests__/__snapshots__/UserLink.test.js.snap
deleted file mode 100644
index 15e25367..00000000
--- a/vnext/src/components/__tests__/__snapshots__/UserLink.test.js.snap
+++ /dev/null
@@ -1,33 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`UserLink renders correctly 1`] = `
-Array [
- <a
- className="info-avatar"
- href="/ugnich/"
- onClick={[Function]}
- >
- <img
- src="https://juick.com/i/a/1-deadbeef.png"
- />
- ugnich
- </a>,
- <a
- className="info-avatar"
- href="/ugnich/"
- onClick={[Function]}
- >
- <img
- src="https://juick.com/i/a/1-deadbeef.png"
- />
- ugnich
- </a>,
- <a
- className="info-avatar"
- href="https://example.com/u/test"
- >
- <img />
-
- </a>,
-]
-`;