Fix Messages layout

This commit is contained in:
Bojan Mojsilovic 2024-01-08 18:24:29 +01:00
parent 6119b47820
commit d8f7efdeb1
4 changed files with 247 additions and 230 deletions

View File

@ -95,14 +95,14 @@
>div { >div {
position: fixed; position: fixed;
width: var(--left-col-w); width: var(--right-col-w);
display: grid; display: grid;
grid-template-rows: var(--header-height) 1fr 82px; grid-template-rows: var(--header-height) 1fr 82px;
height: 100%; height: 100%;
border-left: 1px solid var(--devider); border-left: 1px solid var(--devider);
} }
&.messagesHeader { &.messagesColumn {
>div { >div {
border-left: none; border-left: none;
} }
@ -110,6 +110,7 @@
} }
.messagesSearch { .messagesSearch {
width: calc(var(--right-col-w) + 8px);
border-right: 1px solid var(--devider); border-right: 1px solid var(--devider);
} }
@ -135,6 +136,14 @@
height: 52px; height: 52px;
} }
} }
&.messagesHeader {
width: calc(var(--right-col-w) + 8px);
>div {
width: calc(var(--right-col-w) + 8px);
}
}
} }
.rightContent { .rightContent {

View File

@ -136,9 +136,9 @@ const Layout: Component = () => {
</div> </div>
<div class={`${styles.rightColumn} ${location.pathname.startsWith('/messages') ? styles.messagesHeader : ''}`}> <div class={`${styles.rightColumn} ${location.pathname.startsWith('/messages') ? styles.messagesColumn : ''}`}>
<div> <div>
<div class={styles.rightHeader}> <div class={`${styles.rightHeader} ${location.pathname.startsWith('/messages') ? styles.messagesHeader : ''}`}>
<div id="search_section" class={location.pathname.startsWith('/messages') ? styles.messagesSearch : ''}> <div id="search_section" class={location.pathname.startsWith('/messages') ? styles.messagesSearch : ''}>
</div> </div>
</div> </div>

View File

@ -57,184 +57,190 @@
.messagesContent { .messagesContent {
position: relative; position: relative;
.sendersHeader { display: flex;
height: 48px; width: calc(var(--left-col-w) + var(--right-col-w) + 424px);
.senders {
width: 334px; width: 334px;
background: none;
border-radius: 0; .sendersHeader {
border: 1px solid var(--devider); height: 48px;
display: flex; width: 100%;
justify-content: space-between; background: none;
align-items: center; border-radius: 0;
padding-top: 16px; border: 1px solid var(--devider);
padding-left: 8px;
padding-right: 24px;
margin-bottom: 0;
.senderCategorySelector {
display: flex; display: flex;
.categorySelector { justify-content: space-between;
position: relative; align-items: center;
border: none; padding-top: 16px;
outline: none; padding-left: 8px;
padding-block: 0; padding-right: 24px;
padding-inline: 16px; margin-bottom: 0;
margin: 0; .senderCategorySelector {
background: none; display: flex;
color: var(--text-primary); .categorySelector {
font-size: 14px; position: relative;
font-weight: 400; border: none;
line-height: 14px;
text-transform: uppercase;
.indicator {
visibility: hidden;
border-radius: 2px 0px;
width: 100%;
height: 4px;
margin-top: 12px;
background-color: var(--accent);
}
&:focus {
background: none;
box-shadow: none;
outline: none; outline: none;
} padding-block: 0;
padding-inline: 16px;
&.highlight { margin: 0;
background: none;
color: var(--text-primary); color: var(--text-primary);
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 400;
line-height: 14px; line-height: 14px;
text-transform: uppercase;
.indicator { .indicator {
visibility: visible; visibility: hidden;
border-radius: 2px 0px; border-radius: 2px 0px;
width: 100%; width: 100%;
height: 4px; height: 4px;
margin-top: 12px; margin-top: 12px;
background-color: var(--accent); background-color: var(--accent);
} }
&:focus {
background: none;
box-shadow: none;
outline: none;
}
&.highlight {
color: var(--text-primary);
font-size: 14px;
font-weight: 600;
line-height: 14px;
.indicator {
visibility: visible;
border-radius: 2px 0px;
width: 100%;
height: 4px;
margin-top: 12px;
background-color: var(--accent);
}
}
}
.separator {
border-left: 1px solid var(--subtile-devider);
margin-inline: 8px;
}
}
.markAsRead {
display: flex;
align-items: flex-start;
justify-content: center;
height: 30px;
border: none;
outline: none;
padding: 0;
margin: 0;
background: none;
color: var(--accent);
font-size: 14px;
font-weight: 400;
line-height: 16px;
width: auto;
&:focus {
background: none;
box-shadow: none;
outline: none;
}
}
}
.sendersList {
display: flex;
flex-direction: column;
overflow-y: scroll;
overflow-y: overlay;
overflow-x: hidden;
width: 100%;
height: calc(100vh - 176px);
// padding-right: 8px;
border-radius: 0;
border-left: 1px solid var(--devider);
.senderItem {
position: relative;
display: flex;
background-color: var(--background-card);
padding-inline: 15px;
padding-block: 12px;
border-radius: 0;
border: none;
border-bottom: 1px solid var(--devider);
margin-bottom: 0px;
align-items: center;
width: 334px;
&:hover, &.selected, &.focus {
background-color: var(--background-input);
box-shadow: none;
outline: none;
} }
} .senderInfo {
.separator { margin-left: 12px;
border-left: 1px solid var(--subtile-devider);
margin-inline: 8px;
}
}
.markAsRead {
display: flex;
align-items: flex-start;
justify-content: center;
height: 30px;
border: none;
outline: none;
padding: 0;
margin: 0;
background: none;
color: var(--accent);
font-size: 14px;
font-weight: 400;
line-height: 16px;
width: auto;
&:focus {
background: none;
box-shadow: none;
outline: none;
}
}
}
.sendersList {
display: flex;
flex-direction: column;
overflow-y: scroll;
width: 334px;
height: calc(100vh - 176px);
padding-right: 8px;
border-radius: 0;
border-left: 1px solid var(--devider);
.senderItem {
position: relative;
display: flex;
background-color: var(--background-card);
padding-inline: 15px;
padding-block: 12px;
border-radius: 0;
border: none;
border-bottom: 1px solid var(--devider);
margin-bottom: 0px;
align-items: center;
&:hover, &.selected, &.focus {
background-color: var(--background-input);
box-shadow: none;
outline: none;
}
.senderInfo {
margin-left: 12px;
display: flex;
flex-direction: column;
.firstLine {
display: flex; display: flex;
justify-content: flex-start; flex-direction: column;
align-items: center; .firstLine {
.senderName { display: flex;
color: var(--text-primary); justify-content: flex-start;
font-size: 16px; align-items: center;
font-weight: 700; .senderName {
color: var(--text-primary);
font-size: 16px;
font-weight: 700;
line-height: 16px;
max-width: 178px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.dotSeparator {
width: 4px;
height: 4px;
margin-inline: 6px;
border-radius: 2px;
background-color: var(--text-tertiary-2);
}
.lastMessageTime {
color: var(--text-tertiary-2);
font-size: 16px;
font-weight: 400;
line-height: 16px;
}
}
.secondLine {
text-align: left;
color: var(--text-tertiary);
font-weight: 400;
font-size: 14px;
line-height: 16px; line-height: 16px;
max-width: 178px; margin-top: 4px;
overflow: hidden; padding: 0;
max-width: 228px;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden;
} }
.dotSeparator {
width: 4px;
height: 4px;
margin-inline: 6px;
border-radius: 2px;
background-color: var(--text-tertiary-2);
}
.lastMessageTime {
color: var(--text-tertiary-2);
font-size: 16px;
font-weight: 400;
line-height: 16px;
}
}
.secondLine {
text-align: left;
color: var(--text-tertiary);
font-weight: 400;
font-size: 14px;
line-height: 16px;
margin-top: 4px;
padding: 0;
max-width: 228px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
} }
} }
} }
} }
.conversation { .conversation {
position: absolute;
top: 0;
left: 320px;
background-color: var(--background-card ); background-color: var(--background-card );
width: 628px;
height: calc(100vh - var(--header-height)); height: calc(100vh - var(--header-height));
overflow: hidden;
display: flex; display: flex;
flex-direction: column-reverse; flex-direction: column-reverse;
@ -290,7 +296,7 @@
.newMessage { .newMessage {
width: 100%; width: 100%;
position: relative; position: relative;
vertical-align: bottom; align-items: flex-end;
display: flex; display: flex;
border-radius: 0; border-radius: 0;
border: 1px solid var(--devider); border: 1px solid var(--devider);
@ -302,7 +308,7 @@
padding: 1px; padding: 1px;
border-radius: 8px; border-radius: 8px;
width: 538px; width: 538px;
height: 34px; height: 40px;
box-sizing: border-box; box-sizing: border-box;
textarea { textarea {

View File

@ -323,37 +323,37 @@ const Messages: Component = () => {
const onExpandableTextareaInput = () => { const onExpandableTextareaInput = () => {
const maxHeight = 800; const maxHeight = 800;
const elm = newMessageInput as AutoSizedTextArea; const input = newMessageInput as AutoSizedTextArea;
if(!elm || elm.nodeName !== 'TEXTAREA') { if(!input || input.nodeName !== 'TEXTAREA') {
return; return;
} }
const minRows = parseInt(elm.getAttribute('data-min-rows') || '0'); const minRows = parseInt(input.getAttribute('data-min-rows') || '0');
!elm._baseScrollHeight && getScrollHeight(elm); !input._baseScrollHeight && getScrollHeight(input);
if (elm.scrollHeight >= (maxHeight / 3)) { if (input.scrollHeight >= (maxHeight / 3)) {
return; return;
} }
elm.rows = minRows; input.rows = minRows;
const rows = elm.value === '' ? 0 : Math.ceil((elm.scrollHeight - elm._baseScrollHeight) / 20); const rows = input.value === '' ? 0 : Math.ceil((input.scrollHeight - input._baseScrollHeight) / 20);
elm.rows = minRows + rows; input.rows = minRows + rows;
elm.style.height = `${40 + (20 * rows)}px`; input.style.height = `${40 + (20 * rows)}px`;
if (newMessageWrapper) { if (newMessageWrapper) {
newMessageWrapper.style.height = `${80 + (20 * rows)}px`; newMessageWrapper.style.height = `${80 + (20 * rows)}px`;
} }
if (newMessageInputBorder) { if (newMessageInputBorder) {
newMessageInputBorder.style.height = `${82 + (20 * rows)}px`; newMessageInputBorder.style.height = `${42 + (20 * rows)}px`;
} }
// debounce(() => { // debounce(() => {
setMessage(elm.value) setMessage(input.value)
// }, 300); // }, 300);
} }
@ -909,77 +909,79 @@ const Messages: Component = () => {
<div class={styles.messagesContent}> <div class={styles.messagesContent}>
<div class={styles.sendersHeader}> <div class={styles.senders}>
<div class={styles.senderCategorySelector}> <div class={styles.sendersHeader}>
<div class={styles.senderCategorySelector}>
<button
class={`${styles.categorySelector} ${messages?.senderRelation === 'follows' ? styles.highlight : ''}`}
onClick={() => messages?.actions.changeSenderRelation('follows')}
>
<div>
{intl.formatMessage(tMessages.follows)}
</div>
<div class={styles.indicator}></div>
<Show when={messages?.senderRelation === 'other' && messages?.hasMessagesInDifferentTab}>
<div class={styles.bubble}></div>
</Show>
</button>
<button
class={`${styles.categorySelector} ${messages?.senderRelation === 'other' ? styles.highlight : ''}`}
onClick={() => messages?.actions.changeSenderRelation('other')}
>
<div>
{intl.formatMessage(tMessages.other)}
</div>
<div class={styles.indicator}></div>
<Show when={messages?.senderRelation === 'follows' && messages?.hasMessagesInDifferentTab}>
<div class={styles.bubble}></div>
</Show>
</button>
</div>
<button <button
class={`${styles.categorySelector} ${messages?.senderRelation === 'follows' ? styles.highlight : ''}`} class={styles.markAsRead}
onClick={() => messages?.actions.changeSenderRelation('follows')} disabled={!messages?.messageCount}
onClick={markAllAsRead}
> >
<div> {intl.formatMessage(tMessages.markAsRead)}
{intl.formatMessage(tMessages.follows)}
</div>
<div class={styles.indicator}></div>
<Show when={messages?.senderRelation === 'other' && messages?.hasMessagesInDifferentTab}>
<div class={styles.bubble}></div>
</Show>
</button>
<button
class={`${styles.categorySelector} ${messages?.senderRelation === 'other' ? styles.highlight : ''}`}
onClick={() => messages?.actions.changeSenderRelation('other')}
>
<div>
{intl.formatMessage(tMessages.other)}
</div>
<div class={styles.indicator}></div>
<Show when={messages?.senderRelation === 'follows' && messages?.hasMessagesInDifferentTab}>
<div class={styles.bubble}></div>
</Show>
</button> </button>
</div> </div>
<button
class={styles.markAsRead}
disabled={!messages?.messageCount}
onClick={markAllAsRead}
>
{intl.formatMessage(tMessages.markAsRead)}
</button>
</div>
<div class={styles.sendersList} ref={sendersListElement}> <div class={styles.sendersList} ref={sendersListElement}>
<For each={messages?.orderedSenders() || []}> <For each={messages?.orderedSenders() || []}>
{ {
(sender) => ( (sender) => (
<button <button
class={`${styles.senderItem} ${isSelectedSender(sender.npub) ? styles.selected : ''}`} class={`${styles.senderItem} ${isSelectedSender(sender.npub) ? styles.selected : ''}`}
onClick={() => selectSender(sender.npub)} onClick={() => selectSender(sender.npub)}
data-user={sender.pubkey} data-user={sender.pubkey}
> >
<Avatar user={sender} size="md" /> <Avatar user={sender} size="md" />
<div class={styles.senderInfo}> <div class={styles.senderInfo}>
<div class={styles.firstLine}> <div class={styles.firstLine}>
<div class={styles.senderName}> <div class={styles.senderName}>
{userName(sender)} {userName(sender)}
</div>
<Show when={messages?.messageCountPerSender[sender.pubkey] && messages?.messageCountPerSender[sender.pubkey].latest_at > 0}>
<div class={styles.dotSeparator}></div>
<div class={styles.lastMessageTime}>
{date(messages?.messageCountPerSender[sender.pubkey].latest_at || 0,'narrow', messages?.now).label}
</div> </div>
</Show> <Show when={messages?.messageCountPerSender[sender.pubkey] && messages?.messageCountPerSender[sender.pubkey].latest_at > 0}>
<div class={styles.dotSeparator}></div>
<div class={styles.lastMessageTime}>
{date(messages?.messageCountPerSender[sender.pubkey].latest_at || 0,'narrow', messages?.now).label}
</div>
</Show>
</div>
<div class={styles.secondLine}>
{nip05Verification(sender)}
</div>
</div> </div>
<div class={styles.secondLine}> <Show when={mgsFromSender(sender) > 0}>
{nip05Verification(sender)} <div class={styles.senderBubble}>
</div> {mgsFromSender(sender)}
</div> </div>
<Show when={mgsFromSender(sender) > 0}> </Show>
<div class={styles.senderBubble}> </button>
{mgsFromSender(sender)} )
</div> }
</Show> </For>
</button> </div>
)
}
</For>
</div> </div>
<div class={styles.conversation}> <div class={styles.conversation}>