Reworked mobile UI for some components

This commit is contained in:
t1enne
2022-07-08 22:20:22 +02:00
parent 37ad329072
commit efbe6907ac
15 changed files with 223 additions and 132 deletions

View File

@@ -65,9 +65,9 @@ export default function ChatContainer(props: Props) {
const MessagesTable = useMemo(
() => (
<>
<div style={{ height: '100%' }}>
<Virtuoso
style={{ height: isMobile ? 500 : '77vh', width: 'auto' }}
style={{ height: '100%', width: 'auto' }}
ref={chatContainerRef}
initialTopMostItemIndex={messages.length - 1} // Force alignment to bottom
data={messages}
@@ -92,7 +92,7 @@ export default function ChatContainer(props: Props) {
</Button>
</div>
)}
</>
</div>
),
[messages, usernameToHighlight, chatUserId, isModerator, atBottom, isMobile],
);

View File

@@ -1,36 +0,0 @@
import { useState } from 'react';
interface Props {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default function ChatTextField(props: Props) {
const [value, setValue] = useState('');
const [showEmojis, setShowEmojis] = useState(false);
return (
<div>
<input
type="text"
value={value}
onChange={e => setValue(e.target.value)}
placeholder="Type a message here then hit ENTER"
/>
<button type="button" onClick={() => setShowEmojis(!showEmojis)}>
<svg
xmlns="http://www.w3.org/2000/svg"
className="icon"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</button>
</div>
);
}

View File

@@ -7,48 +7,62 @@
overflow-x: hidden;
div[role=textbox] {
font-size: 0.9rem;
border-radius: .2rem;
padding: .6rem;
padding-right: calc(0.6rem + 44px);
border-radius: .35rem;
background-color: var(--color-owncast-gray-700);
box-shadow: 0;
transition: box-shadow 50ms ease-in-out;
&:focus {
box-shadow: inset 0px 0px 0x 1px var(--color-owncast-purple-700);
outline: 1px solid var(--color-owncast-gray-500) !important;
}
& > p {
margin: 0px;
}
}
.inputWrapper {
display: flex;
position: relative;
margin-right: .3rem;
border-radius: .2rem;
& > div {
transition: box-shadow .2s ease-in-out;
}
}
.emojiButton {
border: none;
background: none;
cursor: pointer;
padding: 0 1rem;
position: absolute;
right: 0px;
top: 50%;
transform: translateY(-50%);
svg {
fill: var(--color-owncast-gray-300);
}
}
.submitButtonWrapper {
display: flex;
padding: 6px 0;
justify-content: flex-end;
}
}
.inputWrapper {
display: flex;
position: relative;
border-radius: var(--theme-rounded-corners);
outline: 1px solid var(--color-owncast-gray-500);
&:hover {
box-shadow: 0 0 1px 1px var(--color-owncast-gray-300);
}
& > div {
transition: box-shadow .2s ease-in-out;
&:focus {
// box-shadow: 0 0 1px 1px var(--color-owncast-gray-300);
.mobile {
&.root {
display: flex;
.inputWrapper {
flex: 1;
}
.submitButtonWrapper {
padding: 0px;
}
}
}
.emojiButton {
border: none;
background: none;
cursor: pointer;
padding: 0 1rem;
position: absolute;
right: 0px;
top: 50%;
transform: translateY(-50%);
svg {
fill: var(--color-owncast-gray-300);
}
}
.submitButtonWrapper {
display: flex;
padding: 6px 0;
justify-content: flex-end;
}

View File

@@ -4,9 +4,10 @@ import React, { useState } from 'react';
import { useRecoilValue } from 'recoil';
import { Transforms, createEditor, BaseEditor, Text } from 'slate';
import { Slate, Editable, withReact, ReactEditor } from 'slate-react';
import cn from 'classnames';
import EmojiPicker from './EmojiPicker';
import WebsocketService from '../../../services/websocket-service';
import { websocketServiceAtom } from '../../stores/ClientConfigStore';
import { isMobileAtom, websocketServiceAtom } from '../../stores/ClientConfigStore';
import { MessageType } from '../../../interfaces/socket-events';
import s from './ChatTextField.module.scss';
@@ -101,6 +102,7 @@ export default function ChatTextField(props: Props) {
// const { value: originalValue } = props;
const [showEmojis, setShowEmojis] = useState(false);
const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom);
const isMobile = useRecoilValue<boolean>(isMobileAtom);
const [editor] = useState(() => withImages(withReact(createEditor())));
const sendMessage = () => {
@@ -120,7 +122,7 @@ export default function ChatTextField(props: Props) {
const handleChange = () => {};
const handleEmojiSelect = e => {
const handleEmojiSelect = (e: any) => {
ReactEditor.focus(editor);
if (e.url) {
@@ -134,7 +136,7 @@ export default function ChatTextField(props: Props) {
}
};
const onKeyDown = e => {
const onKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
e.preventDefault();
sendMessage();
@@ -142,7 +144,11 @@ export default function ChatTextField(props: Props) {
};
return (
<div className={s.root}>
<div
className={cn(s.root, {
[s.mobile]: isMobile,
})}
>
<div className={s.inputWrapper}>
<Slate
editor={editor}
@@ -167,9 +173,13 @@ export default function ChatTextField(props: Props) {
</button>
</div>
<div className={s.submitButtonWrapper}>
<Button size="middle" type="primary" icon={<SendOutlined />} onClick={sendMessage}>
Send
</Button>
{isMobile ? (
<Button size="large" type="ghost" icon={<SendOutlined />} onClick={sendMessage} />
) : (
<Button type="primary" icon={<SendOutlined />} onClick={sendMessage}>
Send
</Button>
)}
</div>
<Popover
content={<EmojiPicker onEmojiSelect={handleEmojiSelect} />}