Browse Source

reimplementing multiselect chat input animation

master
morethanwords 3 years ago
parent
commit
2ff7c7050f
  1. 12
      src/components/chat/input.ts
  2. 30
      src/components/chat/selection.ts
  3. 254
      src/scss/partials/_chat.scss

12
src/components/chat/input.ts

@ -58,7 +58,7 @@ export default class ChatInput {
public rowsWrapper: HTMLDivElement; public rowsWrapper: HTMLDivElement;
private newMessageWrapper: HTMLDivElement; private newMessageWrapper: HTMLDivElement;
private btnToggleEmoticons: HTMLButtonElement; private btnToggleEmoticons: HTMLButtonElement;
private btnSendContainer: HTMLDivElement; public btnSendContainer: HTMLDivElement;
public attachMenu: HTMLButtonElement; public attachMenu: HTMLButtonElement;
private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: number) => boolean})[]; private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: number) => boolean})[];
@ -128,9 +128,15 @@ export default class ChatInput {
this.inputContainer.classList.add('chat-input-container'); this.inputContainer.classList.add('chat-input-container');
this.rowsWrapper = document.createElement('div'); this.rowsWrapper = document.createElement('div');
this.rowsWrapper.classList.add('rows-wrapper'); this.rowsWrapper.classList.add('rows-wrapper', 'chat-input-wrapper');
this.inputContainer.append(this.rowsWrapper); const fakeRowsWrapper = document.createElement('div');
fakeRowsWrapper.classList.add('fake-wrapper', 'fake-rows-wrapper');
const fakeSelectionWrapper = document.createElement('div');
fakeSelectionWrapper.classList.add('fake-wrapper', 'fake-selection-wrapper');
this.inputContainer.append(this.rowsWrapper, fakeRowsWrapper, fakeSelectionWrapper);
this.chatInput.append(this.inputContainer); this.chatInput.append(this.inputContainer);
this.goDownBtn = Button('bubbles-go-down btn-corner btn-circle z-depth-1 hide', {icon: 'arrow_down'}); this.goDownBtn = Button('bubbles-go-down btn-corner btn-circle z-depth-1 hide', {icon: 'arrow_down'});

30
src/components/chat/selection.ts

@ -21,6 +21,7 @@ export default class ChatSelection {
public selectedMids: Set<number> = new Set(); public selectedMids: Set<number> = new Set();
public isSelecting = false; public isSelecting = false;
private selectionInputWrapper: HTMLElement;
private selectionContainer: HTMLElement; private selectionContainer: HTMLElement;
private selectionCountEl: HTMLElement; private selectionCountEl: HTMLElement;
public selectionSendNowBtn: HTMLElement; public selectionSendNowBtn: HTMLElement;
@ -274,12 +275,27 @@ export default class ChatSelection {
blurActiveElement(); // * for mobile keyboards blurActiveElement(); // * for mobile keyboards
let transform = '';
const forwards = !!this.selectedMids.size || forceSelection; const forwards = !!this.selectedMids.size || forceSelection;
if(forwards) {
const p = this.input.rowsWrapper.parentElement;
const widthFrom = p.querySelector('.fake-rows-wrapper').scrollWidth;
const widthTo = p.querySelector('.fake-selection-wrapper').scrollWidth;
const btnSendWidth = this.input.btnSendContainer.scrollWidth - (.5625 * 16);
if(widthFrom !== widthTo) {
const scale = widthTo / widthFrom;
transform = `translateX(${btnSendWidth * scale}px) scaleX(${scale})`;
//scale = widthTo / widthFrom;
}
}
SetTransition(this.input.rowsWrapper, 'is-centering', forwards, 200); SetTransition(this.input.rowsWrapper, 'is-centering', forwards, 200);
this.input.rowsWrapper.style.transform = transform;
SetTransition(bubblesContainer, 'is-selecting', forwards, 200, () => { SetTransition(bubblesContainer, 'is-selecting', forwards, 200, () => {
if(!this.isSelecting) { if(!this.isSelecting) {
this.selectionContainer.remove(); this.selectionInputWrapper.remove();
this.selectionContainer = this.selectionSendNowBtn = this.selectionForwardBtn = this.selectionDeleteBtn = null; this.selectionInputWrapper = this.selectionContainer = this.selectionSendNowBtn = this.selectionForwardBtn = this.selectionDeleteBtn = null;
this.selectedText = undefined; this.selectedText = undefined;
} }
@ -292,6 +308,9 @@ export default class ChatSelection {
if(this.isSelecting) { if(this.isSelecting) {
if(!this.selectionContainer) { if(!this.selectionContainer) {
this.selectionInputWrapper = document.createElement('div');
this.selectionInputWrapper.classList.add('chat-input-wrapper', 'selection-wrapper');
this.selectionContainer = document.createElement('div'); this.selectionContainer = document.createElement('div');
this.selectionContainer.classList.add('selection-container'); this.selectionContainer.classList.add('selection-container');
@ -329,7 +348,12 @@ export default class ChatSelection {
this.selectionContainer.append(...[btnCancel, this.selectionCountEl, this.selectionSendNowBtn, this.selectionForwardBtn, this.selectionDeleteBtn].filter(Boolean)); this.selectionContainer.append(...[btnCancel, this.selectionCountEl, this.selectionSendNowBtn, this.selectionForwardBtn, this.selectionDeleteBtn].filter(Boolean));
this.input.rowsWrapper.append(this.selectionContainer); this.selectionInputWrapper.style.opacity = '0';
this.selectionInputWrapper.append(this.selectionContainer);
this.input.rowsWrapper.parentElement.append(this.selectionInputWrapper);
void this.selectionInputWrapper.offsetLeft; // reflow
this.selectionInputWrapper.style.opacity = '';
} }
} }

254
src/scss/partials/_chat.scss

@ -203,6 +203,7 @@ $chat-helper-size: 39px;
} }
.btn-send { .btn-send {
transition: .2s transform !important;
color: #9e9e9e; color: #9e9e9e;
z-index: 3; z-index: 3;
@ -358,23 +359,12 @@ $chat-helper-size: 39px;
} }
} }
.bubbles.is-selecting ~ & {
.new-message-wrapper, .pinned-container { .new-message-wrapper, .pinned-container {
html:not(.is-safari) & { opacity: 1;
transition: .1s opacity; transition: opacity .1s 0s;
}
}
.selection-container {
opacity: 0;
}
.btn-send {
html:not(.is-safari) & {
transition: .2s transform;
}
} }
.bubbles.is-selecting ~ & {
.new-message-wrapper { .new-message-wrapper {
pointer-events: none; pointer-events: none;
} }
@ -385,27 +375,15 @@ $chat-helper-size: 39px;
opacity: 0; opacity: 0;
} }
.selection-container { .selection-wrapper {
html:not(.is-safari) & {
animation: fade-in-opacity .1s .1s forwards;
}
html.is-safari & {
opacity: 1; opacity: 1;
} }
}
.rows-wrapper { .rows-wrapper {
max-height: var(--chat-input-size); max-height: var(--chat-input-size);
width: 28.75rem; //box-shadow: none;
//max-width: 28.75rem;
} }
/* .reply-wrapper {
transform: none !important;
border-radius: inherit;
} */
.reply-wrapper { .reply-wrapper {
height: 0 !important; height: 0 !important;
} }
@ -417,15 +395,11 @@ $chat-helper-size: 39px;
.bubbles.is-selecting.backwards ~ & { .bubbles.is-selecting.backwards ~ & {
.new-message-wrapper, .pinned-container { .new-message-wrapper, .pinned-container {
html:not(.is-safari) & { transition: opacity .1s .1s;
transition-delay: .1s;
}
} }
.selection-container { .selection-wrapper {
html:not(.is-safari) & { transition: opacity .1s 0s;
animation: fade-in-backwards-opacity .1s forwards;
}
} }
} }
@ -611,7 +585,7 @@ $chat-helper-size: 39px;
} }
} }
.rows-wrapper { .chat-input-wrapper {
--padding-vertical: .3125rem; --padding-vertical: .3125rem;
--padding-horizontal: .5rem; --padding-horizontal: .5rem;
--padding: var(--padding-vertical) var(--padding-horizontal); --padding: var(--padding-vertical) var(--padding-horizontal);
@ -636,86 +610,128 @@ $chat-helper-size: 39px;
body.animation-level-0 & { body.animation-level-0 & {
transition: none; transition: none;
} }
}
.chat-input.type-pinned & { .selection-wrapper {
width: 17.125rem; position: absolute;
left: 50%;
top: 0;
width: 28.75rem;
transform: translateX(-50%);
border-radius: $border-radius-big;
//z-index: 2;
box-shadow: none;
transition: opacity .1s .1s;
opacity: 0;
.selection-container {
display: flex;
justify-content: space-between;
height: 100%;
//background-color: #ccc;
border-radius: inherit;
padding: inherit;
user-select: none;
font-size: 15px;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
&-count {
color: #000;
font-weight: 500;
flex-grow: 1;
white-space: nowrap;
//padding-left: .5rem;
} }
.chat-input.type-pinned.can-pin & { .btn-icon {
width: 13.125rem; margin: 0 5px 0 6px;
color: #3f454a;
height: 42px;
width: 42px;
line-height: 42px;
} }
&.is-centering { .btn-primary {
html:not(.is-safari) & { height: 2.5rem;
transition: width .2s, max-height .2s, border-bottom-right-radius .1s, transform .2s; width: auto;
@include respond-to(handhelds) {
padding: 0 .5rem;
&:after { &.tgico-send2 {
transition: transform .1s; padding: 0 2px;
} }
} }
html.is-safari & { @media only screen and (max-width: 380px) {
transition: none; font-size: 0;
&:before {
margin: 0;
}
}
} }
//will-change: transform; &-forward {
&:before {
margin-right: 14px;
}
} }
&.is-centering:not(.backwards), &.is-centered { &-delete {
border-bottom-right-radius: 12px; margin-right: .625rem;
transform-origin: left; margin-left: .375rem;
transform: translate3d(25%, 0, 0);
//transform: translate3d(calc(((var(--messages-container-width) - var(--chat-input-padding) * 2) - 100%) / 2), 0, 0);
//transform: translate3d(#{calc(28.75rem / 4)}, 0, 0);
/* html.is-safari & { &:before {
max-width: 28.75rem; margin-right: 10px;
} */ }
/* transform: translateX(-50%); }
left: 50%; }
position: absolute; */ }
// left sidebar (420px) + 728px chat max width .fake-wrapper {
@media only screen and (min-width: $floating-left-sidebar + 1) and (max-width: $large-screen / 4 + $messages-container-width) { position: absolute;
//transform: translateX(calc((100vw - 420px - 100%) / 2 - #{$chat-padding})); z-index: -1;
transform: translate3d(calc((100vw - min(100vw / 2.5, #{$large-screen / 4}) - 100%) / 2 - #{$chat-padding}), 0, 0) !important; visibility: hidden;
} }
@media only screen and (max-width: 728px) { .fake-rows-wrapper {
//transform: translateX(calc((100vw - 420px - 100%) / 2 - #{$chat-padding})); width: calc(100% - var(--chat-input-size) - (var(--padding-horizontal) * 2) - .5625rem);
transform: translate3d(calc((100vw - 100%) / 2 - #{$chat-padding}), 0, 0) !important;
} }
@include respond-to(handhelds) { .fake-selection-wrapper {
transform: translate3d(calc((100vw - 100%) / 2 - #{$chat-padding-handhelds}), 0, 0) !important; width: 460px;
} }
.rows-wrapper {
transform: scaleX(1);
transition: transform .2s, width .2s, max-height .2s, border-bottom-right-radius .1s;
&:after { &:after {
transform: scaleX(-1) translateX(#{.5625rem * 2}); transition: transform .1s;
} }
.chat-input.type-pinned & {
width: 17.125rem;
} }
&.is-centered, &.is-centered.is-centering:not(.backwards) { .chat-input.type-pinned.can-pin & {
transform: translate3d(calc(((var(--messages-container-width) - var(--chat-input-padding) * 2) - 100%) / 2), 0, 0); width: 13.125rem;
} }
// ! Need due to reply transform under the container &.is-centering:not(.backwards), &.is-centered {
&:before { border-bottom-right-radius: 12px;
position: absolute;
z-index: 2; &:after {
left: 0; transform: scaleX(-1) translateX(#{.5625rem * 2});
top: 0; }
bottom: 0;
right: 0;
background: inherit;
content: " ";
display: block;
border-radius: inherit;
} }
/* #chat-input.is-helper-active & { /* &.is-centered, &.is-centered.is-centering:not(.backwards) {
border-top-left-radius: 0; transform: translate3d(calc(((var(--messages-container-width) - var(--chat-input-padding) * 2) - 100%) / 2), 0, 0);
border-top-right-radius: 0;
} */ } */
@include respond-to(handhelds) { @include respond-to(handhelds) {
@ -851,70 +867,6 @@ $chat-helper-size: 39px;
} }
} }
.selection-container {
position: absolute;
left: 0;
top: 0;
height: 100%;
//background-color: #ccc;
border-radius: inherit;
padding: inherit;
user-select: none;
font-size: 15px;
&-count {
color: #000;
font-weight: 500;
flex-grow: 1;
white-space: nowrap;
//padding-left: .5rem;
}
.btn-icon {
margin: 0 5px 0 6px;
color: #3f454a;
height: 42px;
width: 42px;
line-height: 42px;
}
.btn-primary {
height: 2.5rem;
width: auto;
@include respond-to(handhelds) {
padding: 0 .5rem;
&.tgico-send2 {
padding: 0 2px;
}
}
@media only screen and (max-width: 380px) {
font-size: 0;
&:before {
margin: 0;
}
}
}
&-forward {
&:before {
margin-right: 14px;
}
}
&-delete {
margin-right: .625rem;
margin-left: .375rem;
&:before {
margin-right: 10px;
}
}
}
.pinned-container { .pinned-container {
width: 17.125rem; width: 17.125rem;

Loading…
Cancel
Save