Shared media sticky header
Shared media close icon animation New left sidebar icon menu animation Debounce opening right sidebar Fix chat input overflow when multiselecting Fix chat input height when ESG doesn't fit
This commit is contained in:
parent
307fa42c2b
commit
2d6d47f7e8
@ -80,7 +80,7 @@ export default class AppSearchSuper {
|
||||
|
||||
private searchGroupMedia: SearchGroup;
|
||||
|
||||
constructor(public types: {inputFilter: SearchSuperType, name: string}[], public scrollable: Scrollable, public searchGroups?: {[group in SearchGroupType]: SearchGroup}, public asChatList = false) {
|
||||
constructor(public types: {inputFilter: SearchSuperType, name: string}[], public scrollable: Scrollable, public searchGroups?: {[group in SearchGroupType]: SearchGroup}, public asChatList = false, public groupByMonth = true) {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('search-super');
|
||||
|
||||
@ -549,7 +549,7 @@ export default class AppSearchSuper {
|
||||
const method = append ? 'append' : 'prepend';
|
||||
elemsToAppend.forEach(details => {
|
||||
const {element, message} = details;
|
||||
const monthContainer = this.getMonthContainerByTimestamp(message.date, type);
|
||||
const monthContainer = this.getMonthContainerByTimestamp(this.groupByMonth ? message.date : 0, type);
|
||||
element.classList.add('search-super-item');
|
||||
element.dataset.mid = '' + message.mid;
|
||||
element.dataset.peerId = '' + message.peerId;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { findUpTag, whichChild, findUpAsChild } from "../helpers/dom";
|
||||
import { whichChild, findUpAsChild } from "../helpers/dom";
|
||||
import { TransitionSlider } from "./transition";
|
||||
import { ScrollableX } from "./scrollable";
|
||||
import rootScope from "../lib/rootScope";
|
||||
@ -105,4 +105,4 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?
|
||||
}
|
||||
|
||||
return selectTab;
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ export class ScrollableBase {
|
||||
protected onScroll: () => void;
|
||||
|
||||
public isHeavyAnimationInProgress = false;
|
||||
protected needCheckAfterAnimation = false;
|
||||
|
||||
constructor(public el: HTMLElement, logPrefix = '', public container: HTMLElement = document.createElement('div')) {
|
||||
this.container.classList.add('scrollable');
|
||||
@ -74,11 +75,16 @@ export class ScrollableBase {
|
||||
this.isHeavyAnimationInProgress = true;
|
||||
|
||||
if(this.onScrollMeasure) {
|
||||
this.needCheckAfterAnimation = true;
|
||||
window.cancelAnimationFrame(this.onScrollMeasure);
|
||||
}
|
||||
}, () => {
|
||||
this.isHeavyAnimationInProgress = false;
|
||||
this.onScroll();
|
||||
|
||||
if(this.needCheckAfterAnimation) {
|
||||
this.onScroll();
|
||||
this.needCheckAfterAnimation = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -146,6 +152,7 @@ export default class Scrollable extends ScrollableBase {
|
||||
window.cancelAnimationFrame(this.onScrollMeasure);
|
||||
}
|
||||
|
||||
this.needCheckAfterAnimation = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -418,6 +418,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
this.toolsBtn.classList.remove('active');
|
||||
this.backBtn.classList.add('active');
|
||||
this.newBtnMenu.classList.add('is-hidden');
|
||||
this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', true);
|
||||
|
||||
transition(1);
|
||||
};
|
||||
@ -428,6 +429,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
this.backBtn.addEventListener('click', (e) => {
|
||||
this.toolsBtn.classList.add('active');
|
||||
this.backBtn.classList.remove('active');
|
||||
this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', false);
|
||||
|
||||
transition(0);
|
||||
});
|
||||
|
@ -103,7 +103,7 @@ export class AppSidebarRight extends SidebarSlider {
|
||||
this.selectTab(AppSidebarRight.SLIDERITEMSIDS.sharedMedia);
|
||||
}
|
||||
|
||||
const transitionTime = rootScope.settings.animationsEnabled ? mediaSizes.isMobile ? 250 : 200 : 0;
|
||||
const transitionTime = rootScope.settings.animationsEnabled ? (mediaSizes.isMobile ? 250 : 200) : 0;
|
||||
const promise = pause(transitionTime);
|
||||
if(transitionTime) {
|
||||
dispatchHeavyAnimationEvent(promise, transitionTime);
|
||||
|
@ -11,6 +11,9 @@ import AvatarElement from "../../avatar";
|
||||
import Scrollable from "../../scrollable";
|
||||
import { SliderTab } from "../../slider";
|
||||
import CheckboxField from "../../checkbox";
|
||||
import { attachClickEvent, cancelEvent } from "../../../helpers/dom";
|
||||
import appSidebarRight from "..";
|
||||
import { TransitionSlider } from "../../transition";
|
||||
|
||||
let setText = (text: string, el: HTMLDivElement) => {
|
||||
window.requestAnimationFrame(() => {
|
||||
@ -29,7 +32,7 @@ let setText = (text: string, el: HTMLDivElement) => {
|
||||
// TODO: отредактированное сообщение не изменится
|
||||
export default class AppSharedMediaTab implements SliderTab {
|
||||
public container: HTMLElement;
|
||||
public closeBtn: HTMLElement;
|
||||
public closeBtn: HTMLButtonElement;
|
||||
|
||||
private peerId = 0;
|
||||
private threadId = 0;
|
||||
@ -62,7 +65,8 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
|
||||
public init() {
|
||||
this.container = document.getElementById('shared-media-container');
|
||||
this.closeBtn = this.container.querySelector('.sidebar-close-button');
|
||||
this.closeBtn = this.container.querySelector('.sidebar-header .btn-icon');
|
||||
this.closeBtn.classList.add('sidebar-close-button');
|
||||
|
||||
this.profileContentEl = this.container.querySelector('.profile-content');
|
||||
this.profileElements = {
|
||||
@ -86,7 +90,37 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
this.profileElements.notificationsRow.prepend(checkboxField.label);
|
||||
|
||||
this.scroll = new Scrollable(this.container, 'SR', 400);
|
||||
|
||||
|
||||
const HEADER_HEIGHT = 56;
|
||||
const closeIcon = this.closeBtn.firstElementChild as HTMLElement;
|
||||
this.scroll.onAdditionalScroll = () => {
|
||||
const rect = this.searchSuper.nav.getBoundingClientRect();
|
||||
if(!rect.width) return;
|
||||
|
||||
//console.log('daddy issues', this.searchSuper.nav.getBoundingClientRect());
|
||||
|
||||
const top = rect.top;
|
||||
const isSharedMedia = top <= HEADER_HEIGHT;
|
||||
closeIcon.classList.toggle('state-back', isSharedMedia);
|
||||
transition(+isSharedMedia);
|
||||
};
|
||||
|
||||
const transition = TransitionSlider(this.closeBtn.nextElementSibling as HTMLElement, 'slide-fade', 400, null, false);
|
||||
|
||||
transition(0);
|
||||
|
||||
attachClickEvent(this.closeBtn, (e) => {
|
||||
if(this.closeBtn.firstElementChild.classList.contains('state-back')) {
|
||||
this.scroll.scrollIntoViewNew(this.scroll.container.firstElementChild as HTMLElement, 'start');
|
||||
transition(0);
|
||||
closeIcon.classList.remove('state-back');
|
||||
} else if(!this.scroll.isHeavyAnimationInProgress) {
|
||||
appSidebarRight.closeTab();
|
||||
}
|
||||
});
|
||||
|
||||
this.container.prepend(this.closeBtn.parentElement);
|
||||
|
||||
this.profileElements.notificationsCheckbox.addEventListener('change', () => {
|
||||
//let checked = this.profileElements.notificationsCheckbox.checked;
|
||||
appMessagesManager.mutePeer(this.peerId);
|
||||
@ -134,7 +168,7 @@ export default class AppSharedMediaTab implements SliderTab {
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterMusic',
|
||||
name: 'Music'
|
||||
}], this.scroll);
|
||||
}], this.scroll/* , undefined, undefined, false */);
|
||||
|
||||
this.profileContentEl.append(this.searchSuper.container);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { attachClickEvent } from "../helpers/dom";
|
||||
import { horizontalMenu } from "./horizontalMenu";
|
||||
import ButtonIcon from "./buttonIcon";
|
||||
import Scrollable from "./scrollable";
|
||||
import { TransitionSlider } from "./transition";
|
||||
|
||||
export interface SliderTab {
|
||||
onOpen?: () => void,
|
||||
@ -86,7 +87,7 @@ export default class SidebarSlider {
|
||||
|
||||
constructor(public sidebarEl: HTMLElement, public tabs: {[id: number]: SliderTab} = {}, private canHideFirst = false) {
|
||||
this.tabsContainer = this.sidebarEl.querySelector('.sidebar-slider');
|
||||
this._selectTab = horizontalMenu(null, this.tabsContainer as HTMLDivElement, null, null, TRANSITION_TIME);
|
||||
this._selectTab = TransitionSlider(this.tabsContainer, 'navigation', TRANSITION_TIME);
|
||||
if(!canHideFirst) {
|
||||
this._selectTab(0);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ function slideTabs(tabContent: HTMLElement, prevTabContent: HTMLElement, toRight
|
||||
};
|
||||
}
|
||||
|
||||
export const TransitionSlider = (content: HTMLElement, type: 'tabs' | 'navigation' | 'zoom-fade' | 'none'/* | 'counter' */, transitionTime: number, onTransitionEnd?: (id: number) => void) => {
|
||||
export const TransitionSlider = (content: HTMLElement, type: 'tabs' | 'navigation' | 'zoom-fade' | 'slide-fade' | 'none'/* | 'counter' */, transitionTime: number, onTransitionEnd?: (id: number) => void, isHeavy = true) => {
|
||||
let animationFunction: TransitionFunction = null;
|
||||
|
||||
switch(type) {
|
||||
@ -62,12 +62,12 @@ export const TransitionSlider = (content: HTMLElement, type: 'tabs' | 'navigatio
|
||||
|
||||
content.dataset.animation = type;
|
||||
|
||||
return Transition(content, animationFunction, transitionTime, onTransitionEnd);
|
||||
return Transition(content, animationFunction, transitionTime, onTransitionEnd, isHeavy);
|
||||
};
|
||||
|
||||
type TransitionFunction = (tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) => void | (() => void);
|
||||
|
||||
const Transition = (content: HTMLElement, animationFunction: TransitionFunction, transitionTime: number, onTransitionEnd?: (id: number) => void) => {
|
||||
const Transition = (content: HTMLElement, animationFunction: TransitionFunction, transitionTime: number, onTransitionEnd?: (id: number) => void, isHeavy = true) => {
|
||||
const onTransitionEndCallbacks: Map<HTMLElement, Function> = new Map();
|
||||
let animationDeferred: CancellablePromise<void>;
|
||||
let animationStarted = 0;
|
||||
@ -84,10 +84,16 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
||||
const callback = onTransitionEndCallbacks.get(e.target as HTMLElement);
|
||||
if(callback) callback();
|
||||
|
||||
if(!animationDeferred || e.target !== from) return;
|
||||
if(e.target !== from) {
|
||||
return;
|
||||
}
|
||||
|
||||
animationDeferred.resolve();
|
||||
animationDeferred = undefined;
|
||||
if(!animationDeferred && isHeavy) return;
|
||||
|
||||
if(animationDeferred) {
|
||||
animationDeferred.resolve();
|
||||
animationDeferred = undefined;
|
||||
}
|
||||
|
||||
if(onTransitionEnd) {
|
||||
onTransitionEnd(selectTab.prevId);
|
||||
@ -180,12 +186,14 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
||||
});
|
||||
}
|
||||
|
||||
if(!animationDeferred) {
|
||||
animationDeferred = deferredPromise<void>();
|
||||
animationStarted = performance.now();
|
||||
if(isHeavy) {
|
||||
if(!animationDeferred) {
|
||||
animationDeferred = deferredPromise<void>();
|
||||
animationStarted = performance.now();
|
||||
}
|
||||
|
||||
dispatchHeavyAnimationEvent(animationDeferred, transitionTime * 2);
|
||||
}
|
||||
|
||||
dispatchHeavyAnimationEvent(animationDeferred, transitionTime * 2);
|
||||
}
|
||||
|
||||
self.prevId = id;
|
||||
|
@ -1,10 +1,12 @@
|
||||
import DEBUG from '../config/debug';
|
||||
import _DEBUG from '../config/debug';
|
||||
import fastBlur from '../vendor/fastBlur';
|
||||
import pushHeavyTask from './heavyQueue';
|
||||
|
||||
const RADIUS = 2;
|
||||
const ITERATIONS = 2;
|
||||
|
||||
const DEBUG = _DEBUG && false;
|
||||
|
||||
function processBlur(dataUri: string, radius: number, iterations: number) {
|
||||
return new Promise<string>((resolve) => {
|
||||
const img = new Image();
|
||||
|
@ -43,7 +43,7 @@ export default function fastSmoothScroll(
|
||||
return Promise.resolve(); */
|
||||
}
|
||||
|
||||
if(axis === 'y' && isInDOM(element) && container.getBoundingClientRect) {
|
||||
if(axis === 'y' && element !== container && isInDOM(element) && container.getBoundingClientRect) {
|
||||
const elementRect = element.getBoundingClientRect();
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
|
||||
|
@ -98,17 +98,18 @@
|
||||
<div class="sidebar-slider-item item-main">
|
||||
<div class="sidebar-header">
|
||||
<div class="sidebar-header__btn-container">
|
||||
<div class="btn-icon tgico-menu btn-menu-toggle rp sidebar-tools-button active">
|
||||
<div class="animated-menu-icon"></div>
|
||||
<div class="btn-icon btn-menu-toggle rp sidebar-tools-button active">
|
||||
<div class="btn-menu bottom-right">
|
||||
<div class="btn-menu-item menu-newGroup tgico-newgroup rp">New Group</div>
|
||||
<div class="btn-menu-item menu-contacts tgico-user rp">Contacts</div>
|
||||
<div class="btn-menu-item menu-archived tgico-archive rp">Archived <span class="archived-count"></span></div>
|
||||
<div class="btn-menu-item menu-archived tgico-archive rp">Archived <span class="archived-count badge badge-24 badge-gray"></span></div>
|
||||
<div class="btn-menu-item menu-saved tgico-savedmessages rp">Saved</div>
|
||||
<div class="btn-menu-item menu-settings tgico-settings rp">Settings</div>
|
||||
<div class="btn-menu-item menu-help tgico-help rp btn-disabled">Help</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-icon tgico-arrow_back rp sidebar-back-button"></div>
|
||||
<div class="btn-icon rp sidebar-back-button"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-content transition zoom-fade">
|
||||
@ -171,9 +172,18 @@
|
||||
<div class="sidebar-content sidebar-slider tabs-container">
|
||||
<div class="sidebar-slider-item profile-container" id="shared-media-container">
|
||||
<div class="sidebar-header">
|
||||
<button class="btn-icon tgico sidebar-close-button"></button>
|
||||
<div class="sidebar-header__title">Info</div>
|
||||
<div class="btn-icon tgico-more"></div>
|
||||
<button class="btn-icon">
|
||||
<div class="animated-close-icon"></div>
|
||||
</button>
|
||||
<div class="transition slide-fade">
|
||||
<div class="transition-item">
|
||||
<div class="sidebar-header__title">Info</div>
|
||||
<div class="btn-icon tgico-more"></div>
|
||||
</div>
|
||||
<div class="transition-item">
|
||||
<div class="sidebar-header__title">Shared Media</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-content">
|
||||
<div class="profile-content-wrapper">
|
||||
|
@ -518,7 +518,13 @@ export class AppImManager {
|
||||
|
||||
if(prevTabId !== -1 && prevTabId !== id && rootScope.settings.animationsEnabled) {
|
||||
const transitionTime = (mediaSizes.isMobile ? 250 : 200) + 100; // * cause transition time could be > 250ms
|
||||
dispatchHeavyAnimationEvent(pause(transitionTime), transitionTime);
|
||||
const promise = pause(transitionTime);
|
||||
dispatchHeavyAnimationEvent(promise, transitionTime);
|
||||
|
||||
this.columnEl.classList.add('disable-hover');
|
||||
promise.finally(() => {
|
||||
this.columnEl.classList.remove('disable-hover');
|
||||
});
|
||||
}
|
||||
|
||||
this.tabId = id;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {isObject} from './bin_utils';
|
||||
import { bigStringInt} from './bin_utils';
|
||||
import {bigStringInt} from './bin_utils';
|
||||
import {TLDeserialization, TLSerialization} from './tl_utils';
|
||||
import CryptoWorker from '../crypto/cryptoworker';
|
||||
import sessionStorage from '../sessionStorage';
|
||||
@ -11,19 +11,13 @@ import { InvokeApiOptions } from '../../types';
|
||||
import { longToBytes } from '../crypto/crypto_utils';
|
||||
import MTTransport from './transports/transport';
|
||||
import { convertToUint8Array, bufferConcat, bytesCmp, bytesToHex } from '../../helpers/bytes';
|
||||
import { nextRandomInt, randomLong } from '../../helpers/random';
|
||||
import { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise';
|
||||
import { isSafari } from '../../helpers/userAgent';
|
||||
import { nextRandomInt } from '../../helpers/random';
|
||||
import { CancellablePromise } from '../../helpers/cancellablePromise';
|
||||
import App from '../../config/app';
|
||||
import DEBUG from '../../config/debug';
|
||||
import Modes from '../../config/modes';
|
||||
import Obfuscation from './transports/obfuscation';
|
||||
|
||||
/// #if MTPROTO_HTTP_UPLOAD
|
||||
// @ts-ignore
|
||||
import HTTP from './transports/http';
|
||||
/// #elif MTPROTO_HTTP
|
||||
// @ts-ignore
|
||||
/// #if MTPROTO_HTTP_UPLOAD || MTPROTO_HTTP
|
||||
import HTTP from './transports/http';
|
||||
/// #endif
|
||||
|
||||
@ -120,8 +114,6 @@ export default class MTPNetworker {
|
||||
|
||||
private debugRequests: Array<{before: Uint8Array, after: Uint8Array}> = [];
|
||||
|
||||
private obfuscation: Obfuscation;
|
||||
|
||||
constructor(public dcId: number, private authKey: number[], private authKeyId: Uint8Array,
|
||||
serverSalt: number[], private transport: MTTransport, options: InvokeApiOptions = {}) {
|
||||
this.authKeyUint8 = convertToUint8Array(this.authKey);
|
||||
@ -715,7 +707,7 @@ export default class MTPNetworker {
|
||||
|
||||
// * correct, fully checked
|
||||
public async getMsgKey(dataWithPadding: ArrayBuffer, isOut: boolean) {
|
||||
const x = isOut ? 0 : 8
|
||||
const x = isOut ? 0 : 8;
|
||||
const msgKeyLargePlain = bufferConcat(this.authKeyUint8.subarray(88 + x, 88 + x + 32), dataWithPadding);
|
||||
|
||||
const msgKeyLarge = await CryptoWorker.sha256Hash(msgKeyLargePlain);
|
||||
@ -980,13 +972,13 @@ export default class MTPNetworker {
|
||||
data.storeInt(message.body.length, 'message_data_length');
|
||||
data.storeRawBytes(message.body, 'message_data');
|
||||
|
||||
const des = new TLDeserialization(data.getBuffer().slice(16));
|
||||
/* const des = new TLDeserialization(data.getBuffer().slice(16));
|
||||
const desSalt = des.fetchLong();
|
||||
const desSessionId = des.fetchLong();
|
||||
|
||||
if(!this.isOnline) {
|
||||
this.log.error('trying to send message when offline', message, new Uint8Array(des.buffer), desSalt, desSessionId);
|
||||
}
|
||||
} */
|
||||
|
||||
/* const messageDataLength = message.body.length;
|
||||
let canBeLength = 0; // bytes
|
||||
@ -1004,14 +996,14 @@ export default class MTPNetworker {
|
||||
} */
|
||||
|
||||
const paddingLength = (16 - (data.offset % 16)) + 16 * (1 + nextRandomInt(5));
|
||||
const padding = (message as any).padding || new Uint8Array(paddingLength).randomize()/* .fill(0) */;
|
||||
const padding = /* (message as any).padding || */new Uint8Array(paddingLength).randomize()/* .fill(0) */;
|
||||
/* const padding = [167, 148, 207, 226, 86, 192, 193, 57, 124, 153, 174, 145, 159, 1, 5, 70, 127, 157,
|
||||
51, 241, 46, 85, 141, 212, 139, 234, 213, 164, 197, 116, 245, 70, 184, 40, 40, 201, 233, 211, 150,
|
||||
94, 57, 84, 1, 135, 108, 253, 34, 139, 222, 208, 71, 214, 90, 67, 36, 28, 167, 148, 207, 226, 86, 192, 193, 57, 124, 153, 174, 145, 159, 1, 5, 70, 127, 157,
|
||||
51, 241, 46, 85, 141, 212, 139, 234, 213, 164, 197, 116, 245, 70, 184, 40, 40, 201, 233, 211, 150,
|
||||
94, 57, 84, 1, 135, 108, 253, 34, 139, 222, 208, 71, 214, 90, 67, 36, 28].slice(0, paddingLength); */
|
||||
|
||||
(message as any).padding = padding;
|
||||
//(message as any).padding = padding;
|
||||
|
||||
const dataWithPadding = bufferConcat(dataBuffer, padding);
|
||||
// this.log('Adding padding', dataBuffer, padding, dataWithPadding)
|
||||
@ -1040,12 +1032,12 @@ export default class MTPNetworker {
|
||||
|
||||
const requestData = request.getBytes(true);
|
||||
|
||||
if(this.isFileNetworker) {
|
||||
//this.log('Send encrypted: requestData length:', requestData.length, requestData.length % 16, paddingLength % 16, paddingLength, data.offset, encryptedResult.msgKey.length % 16, encryptedResult.bytes.length % 16);
|
||||
//this.log('Send encrypted: messageId:', message.msg_id, requestData.length);
|
||||
//this.log('Send encrypted:', message, new Uint8Array(bufferConcat(des.buffer, padding)), requestData, this.serverSalt.hex, this.sessionId.hex/* new Uint8Array(des.buffer) */);
|
||||
this.debugRequests.push({before: new Uint8Array(bufferConcat(des.buffer, padding)), after: requestData});
|
||||
}
|
||||
// if(this.isFileNetworker) {
|
||||
// //this.log('Send encrypted: requestData length:', requestData.length, requestData.length % 16, paddingLength % 16, paddingLength, data.offset, encryptedResult.msgKey.length % 16, encryptedResult.bytes.length % 16);
|
||||
// //this.log('Send encrypted: messageId:', message.msg_id, requestData.length);
|
||||
// //this.log('Send encrypted:', message, new Uint8Array(bufferConcat(des.buffer, padding)), requestData, this.serverSalt.hex, this.sessionId.hex/* new Uint8Array(des.buffer) */);
|
||||
// this.debugRequests.push({before: new Uint8Array(bufferConcat(des.buffer, padding)), after: requestData});
|
||||
// }
|
||||
|
||||
return requestData;
|
||||
});
|
||||
|
81
src/scss/partials/_animatedIcon.scss
Normal file
81
src/scss/partials/_animatedIcon.scss
Normal file
@ -0,0 +1,81 @@
|
||||
.animated-close-icon {
|
||||
position: absolute;
|
||||
transform: rotate(-45deg);
|
||||
pointer-events: none;
|
||||
|
||||
&, &:before, &:after {
|
||||
width: 1.125rem;
|
||||
height: .125rem;
|
||||
border-radius: .125rem;
|
||||
background-color: var(--color-text-secondary);
|
||||
transition: transform var(--slide-header-transition);
|
||||
}
|
||||
|
||||
&:before, &:after {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
content: "";
|
||||
}
|
||||
|
||||
&:before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
&.no-transition {
|
||||
&, &:before, &:after {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.state-back {
|
||||
transform: rotate(180deg);
|
||||
|
||||
&:before {
|
||||
transform: rotate(45deg) scaleX(.75) translateY(-.375rem);
|
||||
}
|
||||
|
||||
&:after {
|
||||
transform: rotate(-45deg) scaleX(.75) translateY(.375rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.animated-menu-icon {
|
||||
position: absolute;
|
||||
|
||||
&, &:before, &:after {
|
||||
width: 1.125rem;
|
||||
height: .125rem;
|
||||
border-radius: .125rem;
|
||||
background-color: var(--color-text-secondary);
|
||||
transition: transform .25s;
|
||||
transform: rotate(0);
|
||||
}
|
||||
|
||||
&:before, &:after {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
content: "";
|
||||
}
|
||||
|
||||
&:before {
|
||||
top: -.3125rem;
|
||||
}
|
||||
|
||||
&:after {
|
||||
top: .3125rem;
|
||||
}
|
||||
|
||||
&.state-back {
|
||||
transform: rotate(180deg);
|
||||
|
||||
&:before {
|
||||
transform: rotate(45deg) scaleX(.75) translate(.375rem, -.1875rem);
|
||||
}
|
||||
|
||||
&:after {
|
||||
transform: rotate(-45deg) scaleX(.75) translate(.375rem, .1875rem);
|
||||
}
|
||||
}
|
||||
}
|
@ -84,11 +84,9 @@ $chat-helper-size: 39px;
|
||||
--padding-horizontal: #{$chat-padding};
|
||||
}
|
||||
|
||||
@include respond-to(esg-bottom) {
|
||||
.btn-circle {
|
||||
height: $chat-input-handhelds-size;
|
||||
width: $chat-input-handhelds-size;
|
||||
}
|
||||
.btn-circle {
|
||||
width: var(--chat-input-size);
|
||||
height: var(--chat-input-size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,6 +374,10 @@ $chat-helper-size: 39px;
|
||||
transition: .2s transform;
|
||||
}
|
||||
}
|
||||
|
||||
.new-message-wrapper {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.bubbles.is-selecting:not(.backwards) ~ & {
|
||||
@ -623,7 +625,7 @@ $chat-helper-size: 39px;
|
||||
border-radius: 12px;
|
||||
border-bottom-right-radius: 0;
|
||||
//box-shadow: 0 1px 2px 0 rgba(16, 35, 47, .07);
|
||||
box-shadow: 0px 1px 8px 1px rgba(0, 0, 0, 0.18);
|
||||
box-shadow: 0px 1px 8px 1px rgba(0, 0, 0, .18);
|
||||
min-height: var(--chat-input-size);
|
||||
max-height: 30rem;
|
||||
flex: 0 0 auto;
|
||||
@ -728,7 +730,6 @@ $chat-helper-size: 39px;
|
||||
@include respond-to(esg-bottom) {
|
||||
--padding-vertical: .5px;
|
||||
--padding-horizontal: .5rem;
|
||||
min-height: $chat-input-handhelds-size;
|
||||
}
|
||||
|
||||
&:after {
|
||||
|
@ -57,6 +57,7 @@
|
||||
border-bottom: 1px solid #dadce0;
|
||||
position: relative;
|
||||
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .16);
|
||||
top: unset;
|
||||
|
||||
.scrollable {
|
||||
position: relative;
|
||||
@ -198,47 +199,39 @@
|
||||
|
||||
.sidebar-header__btn-container {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
> .btn-icon {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transition: .2s opacity, .15s background-color;
|
||||
z-index: 2;
|
||||
|
||||
&:before {
|
||||
transition: .2s transform;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
margin: 0;
|
||||
|
||||
body.animation-level-0 &, body.animation-level-0 &:before {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
& + * {
|
||||
margin-left: 0!important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
//margin-top: 1px;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
color: #707579;
|
||||
|
||||
&:before {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-menu {
|
||||
@include respond-to(handhelds) {
|
||||
margin-top: -4px;
|
||||
margin-top: -.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -247,20 +240,10 @@
|
||||
min-width: 217px;
|
||||
|
||||
.archived-count {
|
||||
border-radius: 12px;
|
||||
min-width: 24px;
|
||||
padding: 0 8px;
|
||||
height: 24px;
|
||||
text-align: center;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
background-color: #c5c9cc;
|
||||
justify-self: flex-end;
|
||||
margin-left: .625rem;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@
|
||||
.sidebar-header {
|
||||
flex: 0 0 auto;
|
||||
|
||||
.sidebar-close-button:before {
|
||||
.sidebar-close-button.tgico:before {
|
||||
content: $tgico-arrow_back;
|
||||
|
||||
@include respond-to(not-handhelds) {
|
||||
@ -235,6 +235,15 @@
|
||||
max-height: calc((var(--vh, 1vh) * 100) - 100% - 56px);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-header .transition {
|
||||
flex-grow: 1;
|
||||
|
||||
.transition-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-super {
|
||||
@ -278,7 +287,7 @@
|
||||
box-shadow: none !important;
|
||||
position: -webkit-sticky !important;
|
||||
position: sticky !important;
|
||||
top: 0;
|
||||
top: -1px;
|
||||
z-index: 2;
|
||||
background-color: #fff;
|
||||
|
||||
|
@ -47,8 +47,10 @@ $chat-padding-handhelds: .5rem;
|
||||
--color-gray-hover: #{hover-color($color-gray)};
|
||||
--color-blue-hover: #{hover-color($color-blue)};
|
||||
--color-red-hover: #{hover-color($color-red)};
|
||||
--color-text-secondary: #{$color-gray};
|
||||
--pm-transition: .2s ease-in-out;
|
||||
--layer-transition: .2s ease-in-out;
|
||||
--slide-header-transition: .4s ease-in-out;
|
||||
--tabs-transition: .25s ease-in-out;
|
||||
//--layer-transition: .3s cubic-bezier(.33, 1, .68, 1);
|
||||
//--layer-transition: none;
|
||||
@ -93,6 +95,10 @@ $chat-padding-handhelds: .5rem;
|
||||
--chat-input-padding: #{$chat-padding};
|
||||
}
|
||||
|
||||
@include respond-to(esg-bottom) {
|
||||
--chat-input-size: #{$chat-input-handhelds-size};
|
||||
}
|
||||
|
||||
@include respond-to(only-medium-screens) {
|
||||
--right-column-width: 25vw;
|
||||
}
|
||||
@ -101,6 +107,7 @@ $chat-padding-handhelds: .5rem;
|
||||
@import "partials/ico";
|
||||
@import "partials/input";
|
||||
@import "partials/button";
|
||||
@import "partials/animatedIcon";
|
||||
@import "partials/badge";
|
||||
@import "partials/checkbox";
|
||||
@import "partials/chatlist";
|
||||
@ -847,6 +854,9 @@ img.emoji {
|
||||
}
|
||||
|
||||
.transition {
|
||||
--easeOutSine: cubic-bezier(.39, .575, .565, 1);
|
||||
--easeInSine: cubic-bezier(.47, 0, .745, .715);
|
||||
|
||||
.transition-item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -905,6 +915,57 @@ img.emoji {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* slide-fade
|
||||
*/
|
||||
&.slide-fade {
|
||||
position: relative;
|
||||
|
||||
> .from {
|
||||
transform-origin: left center;
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
> .to {
|
||||
transform-origin: left center;
|
||||
transform: translateX(1.5rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&.animating {
|
||||
> .from {
|
||||
animation: fade-out-opacity .4s ease-out, slide-fade-out-move .4s;
|
||||
}
|
||||
|
||||
> .to {
|
||||
animation: fade-in-opacity .4s var(--easeInSine), slide-fade-in-move .4s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.slide-fade.backwards {
|
||||
> .from {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
> .to {
|
||||
transform: translateX(-1.5rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&.animating {
|
||||
> .from {
|
||||
animation: fade-in-backwards-opacity .4s ease-out, slide-fade-in-backwards-move .4s;
|
||||
}
|
||||
|
||||
> .to {
|
||||
animation: fade-out-backwards-opacity .4s var(--easeOutSine), slide-fade-out-backwards-move .4s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -937,6 +998,45 @@ img.emoji {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* slide-fade
|
||||
*/
|
||||
@keyframes slide-fade-in-move {
|
||||
0% {
|
||||
transform: translateX(1.5rem);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-fade-out-move {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-1.5rem);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-fade-in-backwards-move {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(1.5rem);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-fade-out-backwards-move {
|
||||
0% {
|
||||
transform: translateX(-1.5rem);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* .zoom-fade {
|
||||
transition: .15s ease-in-out opacity, .15s ease-in-out transform;
|
||||
transform: scale3d(1.1, 1.1, 1);
|
||||
|
Loading…
Reference in New Issue
Block a user