Skip to content

Commit

Permalink
feat(ui): update animations, remove full size connection view
Browse files Browse the repository at this point in the history
  • Loading branch information
ph1p committed Apr 25, 2020
1 parent 977b877 commit 4abee19
Show file tree
Hide file tree
Showing 8 changed files with 299 additions and 227 deletions.
22 changes: 13 additions & 9 deletions src/Ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { state, view } from './shared/state';
import { sendMainMessage } from './shared/utils';
// views
import ChatView from './views/Chat';
import ConnectionView from './views/Connection';
import MinimizedView from './views/Minimized';
import UserListView from './views/UserList';

Expand All @@ -43,17 +42,28 @@ onmessage = (message) => {
const GlobalStyle = createGlobalStyle`
body {
overflow: hidden;
text-shadow: 1px 1px 1px rgba(0,0,0,0.004);
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
}
`;

const AppWrapper = styled.div`
overflow: hidden;
`;

let socket: SocketIOClient.Socket;

const init = (serverUrl) => {
state.url = serverUrl;
state.status = ConnectionEnum.NONE;

if(socket) {
socket.removeAllListeners();
socket.disconnect();
}

const socket: SocketIOClient.Socket = io(serverUrl, {
socket = io(serverUrl, {
reconnectionAttempts: 3,
forceNew: true,
transports: ['websocket'],
Expand Down Expand Up @@ -121,17 +131,11 @@ const init = (serverUrl) => {
<Route exact path="/minimized">
<MinimizedView />
</Route>
<Route exact path="/connecting">
<ConnectionView retry={init} text="connecting..." />
</Route>
<Route exact path="/connection-error">
<ConnectionView retry={init} text="connection error :( " />
</Route>
<Route path="/user-list">
<UserListView />
</Route>
<Route path="/">
<ChatView retry={init} />
<ChatView init={init} />
</Route>
</Switch>
</Router>
Expand Down
135 changes: 97 additions & 38 deletions src/components/Chatbar.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import React, { FunctionComponent, useState, useEffect, useRef } from 'react';
import { useRouteMatch } from 'react-router-dom';
import styled from 'styled-components';
import { state } from '../shared/state';
import { state, view } from '../shared/state';
import { sendMainMessage } from '../shared/utils';
import { SharedIcon } from '../shared/style';
import ColorPicker from './ColorPicker';
import { ConnectionEnum } from '../shared/interfaces';

interface ChatProps {
socket: SocketIOClient.Socket;
sendMessage: (event: any) => void;
setTextMessage: (text: string) => void;
textMessage: string;
setSelectionIsChecked: (event: any) => void;
selectionIsChecked: boolean;
init?: (url: string) => void;
}

const ChatBar: FunctionComponent<ChatProps> = (props) => {
Expand All @@ -20,6 +23,9 @@ const ChatBar: FunctionComponent<ChatProps> = (props) => {
const [show, setShow] = useState(hasSelection);
const chatTextInput = useRef(null);

const isFailed = state.status === ConnectionEnum.ERROR;
const isConnected = state.status === ConnectionEnum.CONNECTED;

useEffect(() => {
if (hasSelection) {
setShow(true);
Expand All @@ -40,7 +46,19 @@ const ChatBar: FunctionComponent<ChatProps> = (props) => {
chatTextInput.current.value = '';
}}
>
{false ? (
{!isConnected && (
<ConnectionInfo>
{isFailed ? (
<>
connection failed{' '}
<span onClick={() => props.init(state.url)}>retry</span>
</>
) : (
'connecting...'
)}
</ConnectionInfo>
)}
{/* {false ? (
<SelectionInfo
hasSelection={hasSelection}
onAnimationEnd={onAnimationEnd}
Expand Down Expand Up @@ -74,54 +92,96 @@ const ChatBar: FunctionComponent<ChatProps> = (props) => {
</SelectionInfo>
) : (
''
)}
<ChatInput hasSelection={hasSelection}>
<BellIcon>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 15 16"
>
<path
fill="#5751FF"
fillRule="evenodd"
d="M11 5v4l1 1H2l1-1V5a4 4 0 018 0zm1 4a2 2 0 002 2H0a2 2 0 002-2V5a5 5 0 0110 0v4zm-5 5l-2-2H4a3 3 0 106 0H9l-2 2z"
clipRule="evenodd"
)} */}
{isConnected && (
<>
<ChatInput hasSelection={hasSelection}>
<BellIcon
onClick={() =>
(state.settings.enableNotificationSound = !state.settings
.enableNotificationSound)
}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 15 16"
>
{state.settings.enableNotificationSound ? (
<path
fill={state.settings.color}
fillRule="evenodd"
d="M11 5v4l1 1H2l1-1V5a4 4 0 018 0zm1 4a2 2 0 002 2H0a2 2 0 002-2V5a5 5 0 0110 0v4zm-5 5l-2-2H4a3 3 0 106 0H9l-2 2z"
clipRule="evenodd"
/>
) : (
<path
fill={state.settings.color}
fillRule="evenodd"
d="M4.998 11.472h9.475v-.882a1.76 1.76 0 01-1.764-1.765v-3.53a5.31 5.31 0 00-.134-1.188l-.88.854c.01.11.014.222.014.334v3.53c0 .617.202 1.187.544 1.647H6.027l-1.029 1zm5.718-8.924a4.295 4.295 0 00-7.597 2.747v3.53c0 .604-.194 1.162-.522 1.617l-1.06 1.03H.354v-.882a1.76 1.76 0 001.765-1.765v-3.53a5.295 5.295 0 019.315-3.445l-.718.698zm-5.009 9.807a1.706 1.706 0 103.413 0h1a2.706 2.706 0 11-5.413 0h1zM0 14.146l14-14 .707.708-14 14L0 14.146z"
clipRule="evenodd"
/>
)}
</svg>
</BellIcon>
<input
ref={chatTextInput}
type="input"
onChange={({ target }: any) =>
props.setTextMessage(target.value.substr(0, 1000))
}
placeholder={`Write something ... ${
props.selectionIsChecked ? '(optional)' : ''
}`}
/>
</svg>
</BellIcon>
<input
ref={chatTextInput}
type="input"
onChange={({ target }: any) =>
props.setTextMessage(target.value.substr(0, 1000))
}
placeholder={`Write something ... ${
props.selectionIsChecked ? '(optional)' : ''
}`}
/>
</ChatInput>
<SelectionCheckbox hasSelection={hasSelection}>lol</SelectionCheckbox>
<ColorPicker socket={props.socket} />
</ChatInput>
<SelectionCheckbox hasSelection={hasSelection}>lol</SelectionCheckbox>
</>
)}
</ChatBarForm>
);
};

const ConnectionInfo = styled.div`
display: flex;
justify-content: center;
align-items: center;
position: absolute;
left: 0;
top: 0;
width: 100%;
z-index: 6;
bottom: -5px;
text-align: center;
color: #fff;
font-weight: bold;
span {
text-decoration: underline;
cursor: pointer;
margin-left: 5px;
}
`;

const ChatBarForm = styled.form`
position: absolute;
z-index: 3;
height: 37px;
padding-top: 7px;
right: 14px;
left: 14px;
bottom: 7px;
margin: 0;
transition: transform 0.3s;
transition: transform 0.5s;
transform: translateY(${({ isSettings }) => (isSettings ? 50 : 0)}px);
`;

const SelectionCheckbox = styled.div`
position: absolute;
right: 0;
top: 0;
animation-delay: 0.4s;
transition: all 0.4s;
animation-delay: 0.5s;
transition: all 0.5s;
opacity: ${(p) => (p.hasSelection ? 1 : 0)};
color: #fff;
margin: 7px 14px;
Expand All @@ -133,7 +193,7 @@ const BellIcon = styled.div`
position: absolute;
z-index: 3;
left: 10px;
top: 15px;
top: 8px;
svg {
width: 15px;
height: 16px;
Expand Down Expand Up @@ -187,18 +247,17 @@ const ChatInput = styled.div`
margin: 0;
position: relative;
z-index: 3;
transition: width 0.3s;
width: ${(p) => (p.hasSelection ? '200px' : '100%')};
input {
position: relative;
z-index: 2;
border-radius: 6px;
width: 100%;
border: 0;
padding: 10px 14px 10px 30px;
margin: 7px 0 0;
height: 30px;
outline: none;
transition: width 0.4s;
width: ${(p) => (p.hasSelection ? '200px' : '100%')};
}
button {
border: 0;
Expand All @@ -217,4 +276,4 @@ const ChatInput = styled.div`
}
`;

export default ChatBar;
export default view(ChatBar);
122 changes: 122 additions & 0 deletions src/components/ColorPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React, { useState, useEffect, useRef, FunctionComponent } from 'react';
import styled from 'styled-components';

import { state, view } from '../shared/state';
import { colors } from '../shared/constants';

interface Props {
socket?: SocketIOClient.Socket;
}

const ColorPicker: FunctionComponent<Props> = view((props) => {
const [isOpen, setIsOpen] = useState(false);
const wrapperRef = useRef(null);

useEffect(() => {
function handleClick(event) {
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
setIsOpen(false);
}
}

document.addEventListener('mousedown', handleClick);
return () => document.removeEventListener('mousedown', handleClick);
}, [wrapperRef]);

return (
<Wrapper ref={wrapperRef}>
<CurrentColor
color={state.settings.color}
onClick={() => setIsOpen(!isOpen)}
/>

<Picker isOpen={isOpen}>
{Object.keys(colors).map((color) => (
<div
key={color}
onClick={() =>
state.persistSettings(
{
color,
},
props.socket
)
}
className={`color ${state.settings.color === color && ' active'}`}
style={{ backgroundColor: color }}
/>
))}
</Picker>
</Wrapper>
);
});

const Wrapper = styled.div`
position: absolute;
right: 20px;
top: 10px;
z-index: 4;
`;

const CurrentColor = styled.div`
position: absolute;
width: 12px;
height: 12px;
border-radius: 100%;
background-color: ${({ color }) => color};
cursor: pointer;
`;

const Picker = styled.div`
position: absolute;
pointer-events: ${({ isOpen }) => (isOpen ? 'all' : 'none')};
opacity: ${({ isOpen }) => (isOpen ? 1 : 0)};
background-color: #000;
left: -240px;
top: -51px;
border-radius: 8px;
display: flex;
padding: 10px;
width: 265px;
justify-content: space-between;
&::after {
top: 100%;
right: 11px;
border: solid transparent;
content: ' ';
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-color: transparent;
border-top-color: #000;
border-width: 8px;
margin-left: -8px;
}
.color {
position: relative;
width: 18px;
height: 18px;
border-radius: 100%;
cursor: pointer;
&:hover::after {
background-color: #fff;
}
&.active::after {
background-color: #fff;
}
&::after {
content: '';
position: absolute;
width: 7px;
height: 7px;
top: 50%;
left: 50%;
background-color: transparent;
border-radius: 100%;
transform: translate(-50%, -50%);
}
}
`;

export default ColorPicker;

0 comments on commit 4abee19

Please sign in to comment.