diff --git a/src/components/Inbox/DialogAvatar.module.scss b/src/components/Inbox/DialogAvatar.module.scss new file mode 100644 index 00000000..0bf16d19 --- /dev/null +++ b/src/components/Inbox/DialogAvatar.module.scss @@ -0,0 +1,35 @@ +.DialogAvatar { + width: 40px; + height: 40px; + border-radius: 100%; + display: flex; + align-items: center; + justify-content: center; + position: relative; + + &.online::before { + content: ''; + position: absolute; + background: #2bb452; + width: 8px; + height: 8px; + top: -2px; + right: -2px; + border-radius: 50%; + border: 3px solid #fff; + } + + > img, + > .letter { + display: block; + border-radius: 100%; + } + + > .letter { + margin-bottom: -2px; + font-weight: 500; + font-size: 18px; + line-height: 10px; + color: #fff; + } +} diff --git a/src/components/Inbox/DialogAvatar.tsx b/src/components/Inbox/DialogAvatar.tsx new file mode 100644 index 00000000..7d3788d8 --- /dev/null +++ b/src/components/Inbox/DialogAvatar.tsx @@ -0,0 +1,48 @@ +import { Show, createMemo } from 'solid-js' +import './DialogCard.module.scss' +import styles from './DialogAvatar.module.scss' +import { clsx } from 'clsx' + +type Props = { + url: string + name: string + online?: boolean +} + +const colors = [ + '#001219', + '#005f73', + '#0a9396', + '#94d2bd', + '#ee9b00', + '#ca6702', + '#ae2012', + '#9b2226', + '#668CFF', + '#C34CFE', + '#E699FF', + '#6633FF' +] + +const getById = (letter: string) => + colors[Math.abs(Number(BigInt(letter.toLowerCase().charCodeAt(0) - 97) % BigInt(colors.length)))] + +const DialogAvatar = (props: Props) => { + const nameFirstLetter = props.name.substring(0, 1) + const randomBg = createMemo(() => { + return getById(nameFirstLetter) + }) + + return ( +
+
{nameFirstLetter}
}> + {props.name} +
+
+ ) +} + +export default DialogAvatar diff --git a/src/components/Inbox/DialogCard.module.scss b/src/components/Inbox/DialogCard.module.scss new file mode 100644 index 00000000..23557ec3 --- /dev/null +++ b/src/components/Inbox/DialogCard.module.scss @@ -0,0 +1,65 @@ +.DialogCard { + display: inline-flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + font-size: 14px; + padding: 12px; + transition: background 0.3s ease-in-out; + cursor: pointer; + + &:hover { + background: #f7f7f7; + } + + .avatar { + flex-basis: 40px; + margin-right: 12px; + } + + .body { + flex-basis: 0; + flex-grow: 1; + min-width: 0; + + .name { + color: #141414; + font-weight: 500; + } + + .message { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #9fa1a7; + } + } + + .activity { + font-size: 12px; + margin-left: 12px; + .time { + text-align: right; + color: #ccc; + } + + .counter { + display: flex; + margin-left: auto; + align-items: center; + justify-content: center; + border-radius: 12px; + padding: 0 8px; + background: #d00820; + font-weight: 400; + color: #fff; + width: 22px; + height: 22px; + line-height: 6px; + + > span { + margin-bottom: -2px; + } + } + } +} diff --git a/src/components/Inbox/DialogCard.tsx b/src/components/Inbox/DialogCard.tsx new file mode 100644 index 00000000..75c91b08 --- /dev/null +++ b/src/components/Inbox/DialogCard.tsx @@ -0,0 +1,34 @@ +import './DialogCard.module.scss' +import styles from './DialogCard.module.scss' +import DialogAvatar from './DialogAvatar' +import type { Author } from '../../graphql/types.gen' + +type Props = { + online?: boolean + message?: string + counter?: number +} & Author + +const DialogCard = (props: Props) => { + return ( +
+
+ +
+
+
{props.name}
+
+ Указать предпочтительные языки для результатов поиска можно в разделе +
+
+
+
22:22
+
+ 12 +
+
+
+ ) +} + +export default DialogCard diff --git a/src/components/Inbox/Search.module.scss b/src/components/Inbox/Search.module.scss new file mode 100644 index 00000000..2808aba0 --- /dev/null +++ b/src/components/Inbox/Search.module.scss @@ -0,0 +1,44 @@ +.Search { + .field { + position: relative; + background: #ffffff; + border: 2px solid #e8e8e8; + border-radius: 2px; + overflow: hidden; + + input { + display: block; + height: 40px; + border: none; + box-shadow: none; + padding: 10px 36px 10px 12px; + width: 100%; + font-family: Muller, Arial, Helvetica, sans-serif; + font-style: normal; + font-weight: 400; + font-size: 15px; + + &::placeholder { + color: #858585; + font-family: inherit; + } + &:focus { + outline: none; + & + .icon { + opacity: 0; + right: -30px; + } + } + } + + .icon { + transition: 0.3s ease-in-out; + position: absolute; + width: 16px; + height: 16px; + top: 12px; + right: 12px; + opacity: 0.5; + } + } +} diff --git a/src/components/Inbox/Search.tsx b/src/components/Inbox/Search.tsx new file mode 100644 index 00000000..d180331a --- /dev/null +++ b/src/components/Inbox/Search.tsx @@ -0,0 +1,27 @@ +import styles from './Search.module.scss' +import { createSignal } from 'solid-js' +import { Icon } from '../Nav/Icon' + +type Props = { + placeholder: string + onChange: (value: () => string) => void +} + +const Search = (props: Props) => { + const [value, setValue] = createSignal('') + const search = (event) => { + event.preventDefault() + setValue(event.target.value) + props.onChange(value) + } + return ( +
+
+ + +
+
+ ) +} + +export default Search diff --git a/src/components/Views/Inbox.tsx b/src/components/Views/Inbox.tsx index f970c3e1..fa17a7a6 100644 --- a/src/components/Views/Inbox.tsx +++ b/src/components/Views/Inbox.tsx @@ -1,8 +1,12 @@ -import { For, createSignal, Show, onMount } from 'solid-js' +import { For, createSignal, Show, onMount, createEffect } from 'solid-js' import type { Author } from '../../graphql/types.gen' import { AuthorCard } from '../Author/Card' import { Icon } from '../Nav/Icon' import { Loading } from '../Loading' +import DialogCard from '../Inbox/DialogCard' +import Search from '../Inbox/Search' +import { useAuthorsStore } from '../../stores/zine/authors' + import '../../styles/Inbox.scss' // Для моков import { createClient } from '@urql/core' @@ -16,9 +20,6 @@ const client = createClient({ // chats?: Chat[] // messages?: Message[] // } -const [messages, setMessages] = createSignal([]) -const [postMessageText, setPostMessageText] = createSignal('') -const [loading, setLoading] = createSignal(false) const messageQuery = ` query Comments ($options: PageQueryOptions) { @@ -31,7 +32,6 @@ query Comments ($options: PageQueryOptions) { } } ` - const newMessageQuery = ` mutation postComment($messageBody: String!) { createComment( @@ -44,33 +44,57 @@ mutation postComment($messageBody: String!) { } } ` -const fetchMessages = async (query) => { - const response = await client - .query(query, { - options: { slice: { start: 0, end: 3 } } - }) - .toPromise() - if (response.error) console.debug('getMessages', response.error) - setMessages(response.data.comments.data) -} -const postMessage = async (msg: string) => { - const response = await client.mutation(newMessageQuery, { messageBody: msg }).toPromise() - return response.data.createComment +const userSearch = (array: Author[], keyword: string) => { + const searchTerm = keyword.toLowerCase() + return array.filter((value) => { + return value.name.toLowerCase().match(new RegExp(searchTerm, 'g')) + }) } -let chatWindow -onMount(() => { - setLoading(true) - fetchMessages(messageQuery) - .then(() => { - setLoading(false) - chatWindow.scrollTop = chatWindow.scrollHeight - }) - .catch(() => setLoading(false)) -}) - export const InboxView = () => { + const [messages, setMessages] = createSignal([]) + const [authors, setAuthors] = createSignal([]) + const [postMessageText, setPostMessageText] = createSignal('') + const [loading, setLoading] = createSignal(false) + const { sortedAuthors } = useAuthorsStore() + + createEffect(() => { + setAuthors(sortedAuthors()) + }) + + const getQuery = (query) => { + if (query().length > 2) { + const match = userSearch(authors(), query()) + setAuthors(match) + } else { + setAuthors(sortedAuthors()) + } + } + + const fetchMessages = async (query) => { + const response = await client + .query(query, { + options: { slice: { start: 0, end: 3 } } + }) + .toPromise() + if (response.error) console.debug('getMessages', response.error) + setMessages(response.data.comments.data) + } + const postMessage = async (msg: string) => { + const response = await client.mutation(newMessageQuery, { messageBody: msg }).toPromise() + return response.data.createComment + } + let chatWindow // for scrolling + onMount(async () => { + setLoading(true) + await fetchMessages(messageQuery) + .then(() => { + setLoading(false) + chatWindow.scrollTop = chatWindow.scrollHeight + }) + .catch(() => setLoading(false)) + }) const handleSubmit = async () => { postMessage(postMessageText()) .then((result) => { @@ -82,10 +106,8 @@ export const InboxView = () => { console.log('!!! msg:', messages()) }) } - const handleChangeMessage = (event) => { setPostMessageText(event.target.value) - console.log('!!! asd:', postMessageText().trim().length) } // TODO: get user session @@ -93,11 +115,7 @@ export const InboxView = () => {
- - +
  • @@ -114,18 +132,10 @@ export const InboxView = () => {
-
-
    -
  • - -
    19:48
    -
    - Assumenda delectus deleniti dolores doloribus ducimus, et expedita facere iste laborum, - nihil similique suscipit, ut voluptatem. Accusantium consequuntur doloremque ex molestiae - nemo. -
    -
  • -
+
+ + {(author) => } +
diff --git a/src/styles/Inbox.scss b/src/styles/Inbox.scss index e405cbc1..b64da99f 100644 --- a/src/styles/Inbox.scss +++ b/src/styles/Inbox.scss @@ -29,34 +29,37 @@ main { .author { position: relative; } - - .user--online .author { - &::before { - background: #2bb452; - border: 5px solid #fff; - border-radius: 100%; - content: ''; - height: 5px; - left: 20px; - position: absolute; - top: 0; - width: 5px; - z-index: 1; - } - } - - .circlewrap { - position: absolute; - } } .chat-list { - border-right: 1px solid #141414; display: flex; flex-direction: column; + padding: 0 10px; + height: 100vh; - .author__name { - @include font-size(1.5rem); + .dialogs { + display: flex; + flex-direction: column; + overflow: auto; + height: 100%; + box-sizing: border-box; + position: relative; + + &::before, + &::after { + content: ''; + position: absolute; + height: 10px; + width: 100%; + } + &::before { + top: 0; + background: linear-gradient(to bottom, #fff, transparent 70%); + } + &::after { + bottom: 0; + background: linear-gradient(to top, #fff, transparent 70%); + } } } @@ -66,35 +69,6 @@ main { padding: 1em 0; } -.chat-list__search { - display: flex; - - input, - .button { - border-radius: 2px; - height: 5.6rem; - line-height: 5.6rem; - vertical-align: bottom; - } - - input { - border: 2px solid #e8e8e8; - flex: 1; - @include font-size(1.7rem); - - margin-right: 1.6rem; - padding: 1.6rem 1.2rem; - } - - .button { - @include font-size(4rem); - - font-weight: 100; - padding: 0; - width: 5.6rem; - } -} - .chat-list__types { @include font-size(1.7rem); @@ -119,66 +93,6 @@ main { } } -.chat-list__users { - flex: 1; - position: relative; - - ul { - height: 100%; - list-style: none; - margin: 0; - overflow: auto; - padding: 0; - position: absolute; - width: 100%; - } - - li { - align-items: baseline; - background: #fff; - cursor: pointer; - display: flex; - flex-wrap: wrap; - @include font-size(1.5rem); - - padding: 2.4rem 0.8rem; - position: relative; - transition: background-color 0.3s; - - &:hover { - background: #f6f6f6; - } - } - - .chat-list__user--current { - background: #f6f6f6; - cursor: default; - } - - .author { - flex: 1; - margin-bottom: 0; - } - - .author__details { - margin-left: 4.2rem; - } - - .last-message-date { - color: rgb(0 0 0 / 30%); - @include font-size(1rem); - } - - .last-message-text { - color: rgb(0 0 0 / 30%); - flex: 1 100%; - margin-left: 4.2rem; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } -} - .interlocutor { height: 56px; box-sizing: content-box;