From 01b8e80e0570095de91d1af05c555d1ebee7b534 Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Sun, 9 Feb 2020 13:45:43 +0700 Subject: [PATCH] virtual scroll stickers & right sidebar & pinned dialogs & notify settings --- .DS_Store | Bin 10244 -> 10244 bytes src/components/misc.ts | 14 +- src/components/pageIm.ts | 34 +-- src/components/pageSignIn.ts | 5 +- src/components/scrollable.ts | 244 ++++++++++++++++++++ src/components/scrollable_spliceCount.ts | 270 +++++++++++++++++++++++ src/lib/appManagers/appDialogsManager.ts | 23 +- src/lib/appManagers/appImManager.ts | 205 ++++++++++++----- src/lib/appManagers/appSidebarLeft.ts | 28 ++- src/lib/appManagers/appSidebarRight.ts | 62 +++--- src/lib/appManagers/appUsersManager.ts | 2 +- src/lib/lottieLoader.ts | 22 +- src/lib/mtproto/networker.ts | 4 + src/lib/tl_utils.ts | 8 + src/lib/utils.js | 29 +++ src/scss/partials/_chatlist.scss | 64 +++--- src/scss/partials/_sidebar.scss | 46 ++-- src/scss/style.scss | 3 +- 18 files changed, 881 insertions(+), 182 deletions(-) create mode 100644 src/components/scrollable.ts create mode 100644 src/components/scrollable_spliceCount.ts diff --git a/.DS_Store b/.DS_Store index 102eb72f6e1a93561d5af998dff2b9959512d3a8..8ce924c1067e2d087115d4f83ce177a36c319531 100644 GIT binary patch delta 471 zcmZn(XbG6$jIU^hRb_GBIbdC?jF!GHk-SQzve(it)tN+t&i3oB|M$#B7BfU@Zf zc?|gsMGUDxRq~U~1ym=i2?$Qk70{b}T0mg(Y5|4GtAqq5-xd&`90L@;Ex@^%M{p72 zJah7slXCKtfVu=27#KeTF$c`Wo3+KQ z7}=Q4gH6nqSU9;r#CvkMq$rco_Q`pYA!;9h5)8}?#Xw&qmjxH)<>cq314S5tmIA+G=9a0vP4+{%!Ec0U7%&zc@W${uG%Dg&RTihD}_b7{~ delta 288 zcmY*TKTE?<9Q^%aZ77ZSp0D*a$NheE{;ir7J%>*At#in3BQB;E@)vhI1NTB)rDVJ!+T7uGRx^H$*vU+xw^VAJz(?dd9?67li(6qG { - prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll); + let emojiScroll = new Scrollable(contentEmojiDiv); + emojiScroll.container.addEventListener('scroll', (e) => { + prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll.container); }); + //emojiScroll.setVirtualContainer(emojiScroll.container); - emoticonsMenuOnClick(menu, heights, emojiScroll); + emoticonsMenuOnClick(menu, heights, emojiScroll.container); } let stickersInit = () => { @@ -191,7 +192,7 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement, let menuWrapper = contentStickersDiv.nextElementSibling as HTMLDivElement; let menu = menuWrapper.firstElementChild as HTMLUListElement; - let menuScroll = scrollable(menuWrapper, true, false); + let menuScroll = new Scrollable(menuWrapper, true, false); let stickersDiv = document.createElement('div'); stickersDiv.classList.add('stickers-categories'); @@ -265,6 +266,8 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement, heights[i] = (heights[i - 1] || 0) + div.scrollHeight; }); + //stickersScroll.onScroll(); + //return heights.push(prevHeight + scrollHeight) - 1; }; @@ -342,15 +345,16 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement, }); let prevCategoryIndex = 0; - let stickersScroll = scrollable(contentStickersDiv).container; - stickersScroll.addEventListener('scroll', (e) => { + let stickersScroll = new Scrollable(contentStickersDiv); + stickersScroll.container.addEventListener('scroll', (e) => { lazyLoadQueue.check(); lottieLoader.checkAnimations(); - prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, stickersScroll); + prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, stickersScroll.container); }); + stickersScroll.setVirtualContainer(stickersDiv); - emoticonsMenuOnClick(menu, heights, stickersScroll); + emoticonsMenuOnClick(menu, heights, stickersScroll.container); stickersInit = null; }; @@ -367,8 +371,7 @@ export default () => import('../lib/services').then(services => { let pageEl = document.body.getElementsByClassName('page-chats')[0] as HTMLDivElement; pageEl.style.display = ''; - let sidebarScroll = scrollable(document.body.querySelector('.profile-container')).container; - let chatScroll = scrollable(document.getElementById('bubbles') as HTMLDivElement).container; + let chatScroll = new Scrollable(document.getElementById('bubbles') as HTMLDivElement).container; apiUpdatesManager.attach(); @@ -577,7 +580,7 @@ export default () => import('../lib/services').then(services => { let inputMessageContainer = document.getElementsByClassName('input-message-container')[0] as HTMLDivElement; - let inputScroll = scrollable(inputMessageContainer); + let inputScroll = new Scrollable(inputMessageContainer); let sendMessage = () => { let str = serializeNodes(Array.from(messageInput.childNodes)); @@ -744,6 +747,5 @@ export default () => import('../lib/services').then(services => { appSidebarLeft.loadDialogs().then(result => { appSidebarLeft.onChatsScroll(); appImManager.setScroll(chatScroll); - appSidebarRight.setScroll(sidebarScroll); }); }); diff --git a/src/components/pageSignIn.ts b/src/components/pageSignIn.ts index acdffe88..f17277e0 100644 --- a/src/components/pageSignIn.ts +++ b/src/components/pageSignIn.ts @@ -1,5 +1,6 @@ import { MTProto } from "../lib/mtproto/mtproto"; -import { putPreloader, getNearestDc, scrollable, formatPhoneNumber } from "./misc"; +import { putPreloader, getNearestDc, formatPhoneNumber } from "./misc"; +import Scrollable from './scrollable'; import {RichTextProcessor} from '../lib/richtextprocessor'; import * as Config from '../lib/config'; @@ -51,7 +52,7 @@ export default () => { wrapper.appendChild(list); //let wrapperScroll = OverlayScrollbars(wrapper, (window as any).scrollbarOptions); - scrollable(wrapper); + let scroll = new Scrollable(wrapper); let initedSelect = false; diff --git a/src/components/scrollable.ts b/src/components/scrollable.ts new file mode 100644 index 00000000..a3c4f86a --- /dev/null +++ b/src/components/scrollable.ts @@ -0,0 +1,244 @@ +import { isElementInViewport, isScrolledIntoView } from "../lib/utils"; + +export default class Scrollable { + public container: HTMLDivElement; + public thumb: HTMLDivElement; + + public type: string; + public side: string; + public scrollType: string; + public scrollSide: string; + + public scrollSize = -1; + public size = 0; + public thumbSize = 0; + + public hiddenElements: { + up: Element[], + down: Element[] + } = { + up: [], + down: [] + }; + public paddings = {up: 0, down: 0}; + + public paddingTopDiv: HTMLDivElement; + public paddingBottomDiv: HTMLDivElement; + + public splitUp: HTMLElement; + + /* public topObserver: IntersectionObserver; + public isTopIntersecting: boolean; + public bottomObserver: IntersectionObserver; + public isBottomIntersecting: boolean; */ + + constructor(public el: HTMLDivElement, x = false, y = true) { + this.container = document.createElement('div'); + this.container.classList.add('scrollable'); + + /* this.bottomObserver = new IntersectionObserver(entries => { + let entry = entries[0]; + + this.isBottomIntersecting = entry.intersectionRatio > 0; + + // @ts-ignore + //console.log('bottom instersection:', entry, entry.isVisible, entry.intersectionRatio, entry.isIntersecting); + console.log('bottom intersection:', this.isBottomIntersecting); + }); + + this.topObserver = new IntersectionObserver(entries => { + let entry = entries[0]; + + this.isTopIntersecting = entry.intersectionRatio > 0; + + // @ts-ignore + //console.log('top instersection:', entry, entry.isVisible, entry.intersectionRatio, entry.isIntersecting); + console.log('top intersection:', this.isTopIntersecting); + }); */ + + if(x) { + this.container.classList.add('scrollable-x'); + this.type = 'width'; + this.side = 'left'; + this.scrollType = 'scrollWidth'; + this.scrollSide = 'scrollLeft'; + } else if(y) { + this.container.classList.add('scrollable-y'); + this.type = 'height'; + this.side = 'top'; + this.scrollType = 'scrollHeight'; + this.scrollSide = 'scrollTop'; + } else { + throw new Error('no side for scroll'); + } + + this.thumb = document.createElement('div'); + this.thumb.className = 'scrollbar-thumb'; + + // @ts-ignore + this.thumb.style[this.type] = '30px'; + + this.container.addEventListener('mouseover', this.resize.bind(this)); + window.addEventListener('resize', this.resize.bind(this)); + + this.paddingTopDiv = document.createElement('div'); + this.paddingTopDiv.classList.add('scroll-padding'); + this.paddingBottomDiv = document.createElement('div'); + this.paddingBottomDiv.classList.add('scroll-padding'); + + this.container.addEventListener('scroll', this.onScroll.bind(this)); + + //this.container.append(this.paddingTopDiv); + Array.from(el.children).forEach(c => this.container.append(c)); + //this.container.append(this.paddingBottomDiv); + + el.append(this.container);//container.append(el); + this.container.parentElement.append(this.thumb); + this.resize(); + } + + public resize() { + // @ts-ignore + this.scrollSize = this.container[this.scrollType]; + + let rect = this.container.getBoundingClientRect(); + + // @ts-ignore + this.size = rect[this.type]; + + if(!this.size || this.size == this.scrollSize) { + this.thumbSize = 0; + + // @ts-ignore + this.thumb.style[this.type] = this.thumbSize + 'px'; + return; + } + //if(!height) return; + + let divider = this.scrollSize / this.size / 0.5; + this.thumbSize = this.size / divider; + + if(this.thumbSize < 20) this.thumbSize = 20; + + // @ts-ignore + this.thumb.style[this.type] = this.thumbSize + 'px'; + + // @ts-ignore + //console.log('onresize', thumb.style[type], thumbHeight, height); + } + + public setVirtualContainer(el: HTMLElement) { + this.splitUp = el; + this.hiddenElements = { + up: [], + down: [] + }; + this.paddings = { + up: 0, + down: 0 + }; + + if(this.paddingTopDiv.parentElement) { + this.paddingTopDiv.style.height = ''; + this.paddingBottomDiv.style.height = ''; + } + + //this.topObserver.observe(this.paddingTopDiv); + //this.bottomObserver.observe(this.paddingBottomDiv); + + el.parentElement.insertBefore(this.paddingTopDiv, el); + el.parentNode.insertBefore(this.paddingBottomDiv, el.nextSibling); + } + + public onScroll() { + // @ts-ignore + //let st = container[scrollSide]; + + if(this.container[this.scrollType] != this.scrollSize || this.thumbSize == 0) { + this.resize(); + } + + // @ts-ignore + let value = this.container[this.scrollSide] / (this.scrollSize - this.size) * 100; + let maxValue = 100 - (this.thumbSize / this.size * 100); + + //console.log('onscroll', container.scrollHeight, thumbHeight, height, value, maxValue); + + // @ts-ignore + this.thumb.style[this.side] = (value >= maxValue ? maxValue : value) + '%'; + + if(!this.splitUp) { + return; + } + + let splitUp = this.splitUp; + let children = Array.from(splitUp.children) as HTMLElement[]; + let firstVisible = -1, lastVisible = -1; + let length = children.length; + for(let i = 0; i < length; ++i) { + let child = children[i]; + if(isElementInViewport(child) || isScrolledIntoView(child)) { + if(firstVisible < 0) firstVisible = i; + lastVisible = i; + } + } + + //console.log('onscroll', firstVisible, lastVisible); + + if(firstVisible > 0) { + let sliced = children.slice(0, firstVisible); + + for(let child of sliced) { + this.paddings.up += child.scrollHeight; + this.hiddenElements.up.push(child); + child.parentElement.removeChild(child); + } + + //console.log('onscroll sliced up', sliced.length); + + //sliced.forEach(child => child.style.display = 'none'); + this.paddingTopDiv.style.height = this.paddings.up + 'px'; + //console.log('onscroll need to add padding: ', paddings.up); + } else if(this.hiddenElements.up.length) { + //console.log('onscroll up', isElementInViewport(this.paddingTopDiv), isScrolledIntoView(this.paddingTopDiv), this.paddings.up); + while((isElementInViewport(this.paddingTopDiv) || isScrolledIntoView(this.paddingTopDiv)) && this.paddings.up) { + let child = this.hiddenElements.up.pop(); + + splitUp.prepend(child); + + this.paddings.up -= child.scrollHeight; + this.paddingTopDiv.style.height = this.paddings.up + 'px'; + } + } + + if(lastVisible < (length - 1)) { + let sliced = children.slice(lastVisible + 1).reverse(); + + for(let child of sliced) { + this.paddings.down += child.scrollHeight; + this.hiddenElements.down.unshift(child); + child.parentElement.removeChild(child); + } + + //console.log('onscroll sliced down', splitUp, sliced.length, this.paddings.down + 'px'); + + this.paddingBottomDiv.style.height = this.paddings.down + 'px'; + //console.log('onscroll need to add padding: ', paddings.up); + } else if(this.hiddenElements.down.length) { + //console.log('onscroll down', isElementInViewport(this.paddingBottomDiv), + //isScrolledIntoView(this.paddingBottomDiv), this.paddings.down, this.hiddenElements); + while((isElementInViewport(this.paddingBottomDiv) || isScrolledIntoView(this.paddingBottomDiv)) && this.paddings.down) { + let child = this.hiddenElements.down.shift(); + + splitUp.append(child); + + this.paddings.down -= child.scrollHeight; + this.paddingBottomDiv.style.height = this.paddings.down + 'px'; + } + } + + //console.log('onscroll', container, firstVisible, lastVisible, hiddenElements); + + //lastScrollPos = st; + } +} diff --git a/src/components/scrollable_spliceCount.ts b/src/components/scrollable_spliceCount.ts new file mode 100644 index 00000000..558e1ffb --- /dev/null +++ b/src/components/scrollable_spliceCount.ts @@ -0,0 +1,270 @@ +import { isElementInViewport } from "../lib/utils"; + +export default class Scrollable { + public container: HTMLDivElement; + public thumb: HTMLDivElement; + + public type: string; + public side: string; + public scrollType: string; + public scrollSide: string; + + public scrollSize = -1; + public size = 0; + public thumbSize = 0; + + public hiddenElements: { + up: Element[], + down: Element[] + } = { + up: [], + down: [] + }; + public paddings = {up: 0, down: 0}; + + public paddingTopDiv: HTMLDivElement; + public paddingBottomDiv: HTMLDivElement; + + public splitUp: HTMLElement; + public spliceCount = 1; + public useStylePadding = false; + public useOneHeight = false; + + constructor(public el: HTMLDivElement, x = false, y = true) { + this.container = document.createElement('div'); + this.container.classList.add('scrollable'); + + if(x) { + this.container.classList.add('scrollable-x'); + this.type = 'width'; + this.side = 'left'; + this.scrollType = 'scrollWidth'; + this.scrollSide = 'scrollLeft'; + } else if(y) { + this.container.classList.add('scrollable-y'); + this.type = 'height'; + this.side = 'top'; + this.scrollType = 'scrollHeight'; + this.scrollSide = 'scrollTop'; + } else { + throw new Error('no side for scroll'); + } + + this.thumb = document.createElement('div'); + this.thumb.className = 'scrollbar-thumb'; + + // @ts-ignore + this.thumb.style[this.type] = '30px'; + + this.container.addEventListener('mouseover', this.resize.bind(this)); + window.addEventListener('resize', this.resize.bind(this)); + + this.paddingTopDiv = document.createElement('div'); + this.paddingTopDiv.classList.add('scroll-padding'); + this.paddingBottomDiv = document.createElement('div'); + this.paddingBottomDiv.classList.add('scroll-padding'); + + this.container.addEventListener('scroll', this.onScroll.bind(this)); + + this.container.append(this.paddingTopDiv); + Array.from(el.children).forEach(c => this.container.append(c)); + this.container.append(this.paddingBottomDiv); + + el.append(this.container);//container.append(el); + this.container.parentElement.append(this.thumb); + this.resize(); + } + + public resize() { + // @ts-ignore + this.scrollSize = this.container[this.scrollType]; + + let rect = this.container.getBoundingClientRect(); + + // @ts-ignore + this.size = rect[this.type]; + + if(!this.size || this.size == this.scrollSize) { + this.thumbSize = 0; + + // @ts-ignore + this.thumb.style[this.type] = this.thumbSize + 'px'; + return; + } + //if(!height) return; + + let divider = this.scrollSize / this.size / 0.5; + this.thumbSize = this.size / divider; + + if(this.thumbSize < 20) this.thumbSize = 20; + + // @ts-ignore + this.thumb.style[this.type] = this.thumbSize + 'px'; + + // @ts-ignore + //console.log('onresize', thumb.style[type], thumbHeight, height); + } + + public setVirtualContainer(el: HTMLElement, spliceCount = 1, useStylePadding = false, useOneHeight = false) { + this.splitUp = el; + this.hiddenElements = { + up: [], + down: [] + }; + this.paddings = { + up: 0, + down: 0 + }; + + this.spliceCount = spliceCount; + this.useStylePadding = useStylePadding; + this.useOneHeight = useOneHeight; + + if(this.paddingTopDiv.parentElement) { + this.paddingTopDiv.style.height = ''; + this.paddingBottomDiv.style.height = ''; + } + + + + /* if(useStylePadding) { + this.paddingTopDiv.parentElement.removeChild(this.paddingTopDiv); + this.paddingBottomDiv.parentElement.removeChild(this.paddingBottomDiv); + } else { */ + el.parentElement.insertBefore(this.paddingTopDiv, el); + el.parentNode.insertBefore(this.paddingBottomDiv, el.nextSibling); + //} + + if(useStylePadding) { + this.paddingTopDiv.style.height = '10px'; + this.paddingBottomDiv.style.height = '10px'; + } + } + + public onScroll() { + // @ts-ignore + //let st = container[scrollSide]; + + + if(this.container[this.scrollType] != this.scrollSize || this.thumbSize == 0) { + this.resize(); + } + + // @ts-ignore + let value = this.container[this.scrollSide] / (this.scrollSize - this.size) * 100; + let maxValue = 100 - (this.thumbSize / this.size * 100); + + //console.log('onscroll', container.scrollHeight, thumbHeight, height, value, maxValue); + + // @ts-ignore + this.thumb.style[this.side] = (value >= maxValue ? maxValue : value) + '%'; + + if(!this.splitUp) { + return; + } + + let splitUp = this.splitUp; + let children = Array.from(splitUp.children) as HTMLElement[]; + let firstVisible = -1, lastVisible = -1; + let length = children.length; + for(let i = 0; i < length; ++i) { + let child = children[i]; + if(isElementInViewport(child)) { + if(firstVisible < 0) firstVisible = i; + lastVisible = i; + } + } + + console.log('onscroll', firstVisible, lastVisible); + + if(firstVisible > 0) { + let sliced = children.slice(0, firstVisible); + + let height = 0, singleHeight = sliced[0].scrollHeight; + for(let child of sliced) { + height += child.scrollHeight; + this.hiddenElements.up.push(child); + child.parentElement.removeChild(child); + } + + this.paddings.up += this.useOneHeight ? singleHeight : height; + + //console.log('sliced up', sliced.length); + + //sliced.forEach(child => child.style.display = 'none'); + if(this.useStylePadding) splitUp.style.paddingTop = this.paddings.up + 'px'; + else this.paddingTopDiv.style.height = this.paddings.up + 'px'; + //console.log('onscroll need to add padding: ', paddings.up); + } else if(this.hiddenElements.up.length) { + console.log('onscroll up', isElementInViewport(this.paddingTopDiv), this.paddings.up); + while(isElementInViewport(this.paddingTopDiv) && this.paddings.up) { + //let child = this.hiddenElements.up.pop(); + + /* + splitUp.prepend(...childs); + + this.paddings.up -= child.scrollHeight; + this.paddingTopDiv.style.height = this.paddings.up + 'px';*/ + + let childs = this.hiddenElements.up.splice(-this.spliceCount).reverse(); + + let height = 0; + for(let child of childs) { + splitUp.prepend(child); + height += child.scrollHeight; + } + + this.paddings.up -= this.useOneHeight ? childs[0].scrollHeight : height; + + if(this.useStylePadding) splitUp.style.paddingTop = this.paddings.up + 'px'; + else this.paddingTopDiv.style.height = this.paddings.up + 'px'; + } + } + + if(lastVisible < (length - 1)) { + let sliced = children.slice(lastVisible + 1, this.useOneHeight ? lastVisible + 1 + this.spliceCount : undefined).reverse(); + + let height = 0, singleHeight = sliced[0].scrollHeight; + for(let child of sliced) { + height += child.scrollHeight; + this.hiddenElements.down.unshift(child); + child.parentElement.removeChild(child); + } + + this.paddings.down += this.useOneHeight ? singleHeight : height; + + console.log('onscroll sliced down', splitUp, sliced.length, this.paddings.down + 'px'); + + //sliced.forEach(child => child.style.display = 'none'); + + /* if(this.useStylePadding) splitUp.style.paddingBottom = this.paddings.down + 'px'; + else */ this.paddingBottomDiv.style.height = this.paddings.down + 'px'; + //console.log('onscroll need to add padding: ', paddings.up); + } else if(this.hiddenElements.down.length) { + console.log('onscroll down', isElementInViewport(this.paddingBottomDiv), this.paddings.down, this.hiddenElements); + while(isElementInViewport(this.paddingBottomDiv) && this.paddings.down) { + /* let child = this.hiddenElements.down.shift(); + + splitUp.append(child); + + this.paddings.down -= child.scrollHeight; + this.paddingBottomDiv.style.height = this.paddings.down + 'px'; */ + let childs = this.hiddenElements.down.splice(0, this.spliceCount); + + let height = 0; + for(let child of childs) { + splitUp.append(child); + height += child.scrollHeight; + } + + this.paddings.down -= this.useOneHeight ? childs[0].scrollHeight : height; + /* if(this.useStylePadding) splitUp.style.paddingBottom = this.paddings.down + 'px'; + else */ this.paddingBottomDiv.style.height = this.paddings.down + 'px'; + } + } + + //console.log('onscroll', container, firstVisible, lastVisible, hiddenElements); + + //lastScrollPos = st; + } +} diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 2dbfcab4..772f3d38 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -16,17 +16,23 @@ type DialogDom = { lastTimeSpan: HTMLSpanElement, unreadMessagesSpan: HTMLSpanElement, lastMessageSpan: HTMLSpanElement, + containerEl: HTMLDivElement, listEl: HTMLLIElement }; export class AppDialogsManager { public chatList = document.getElementById('dialogs') as HTMLUListElement; + public pinnedDelimiter: HTMLDivElement; public chatsHidden: any; public myID = 0; public doms: {[x: number]: any} = {}; constructor() { + this.pinnedDelimiter = document.createElement('div'); + this.pinnedDelimiter.classList.add('pinned-delimiter'); + this.pinnedDelimiter.appendChild(document.createElement('span')); + apiManager.getUserID().then((id) => { this.myID = id; }); @@ -168,7 +174,7 @@ export class AppDialogsManager { } else if(this.chatsHidden.down.find((d: HTMLLIElement) => d === dom.listEl)) { inBottom.push(dom.listEl); } else { - console.warn('found no dom!', dom); + //console.warn('found no dom!', dom, d); } //this.chatList.append(dom.listEl); @@ -395,12 +401,22 @@ export class AppDialogsManager { //captionDiv.append(titleSpan); //captionDiv.append(span); + + + let paddingDiv = document.createElement('div'); + paddingDiv.classList.add('rp'); + paddingDiv.append(avatarDiv, captionDiv); + ripple(paddingDiv); + let li = document.createElement('li'); + li.append(paddingDiv); + li.setAttribute('data-peerID', '' + peerID); + /* let li = document.createElement('li'); li.classList.add('rp'); li.append(avatarDiv, captionDiv); li.setAttribute('data-peerID', '' + peerID); - ripple(li); + ripple(li); */ /* let detailsDiv = document.createElement('div'); detailsDiv.classList.add('dialog-details'); */ @@ -432,6 +448,7 @@ export class AppDialogsManager { lastTimeSpan, unreadMessagesSpan, lastMessageSpan: span, + containerEl: paddingDiv, listEl: li }; @@ -441,6 +458,8 @@ export class AppDialogsManager { if(dialog.pFlags.pinned) { li.classList.add('dialog-pinned'); + //this.chatList.insertBefore(this.pinnedDelimiter, li.nextSibling); + dom.listEl.append(this.pinnedDelimiter); } this.doms[dialog.peerID] = dom; diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index 7ab56f8c..fdb593e0 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -101,6 +101,7 @@ export class AppImManager { public myID = 0; public peerID = 0; + public muted = false; public lastDialog: any; public bubbles: {[mid: number]: HTMLDivElement} = {}; @@ -198,54 +199,8 @@ export class AppImManager { $rootScope.$on('apiUpdate', (e: CustomEvent) => { let update = e.detail; - switch(update._) { - case 'updateUserTyping': - case 'updateChatUserTyping': - if(this.myID == update.user_id) { - return; - } - - var peerID = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id; - this.typingUsers[update.user_id] = peerID; - - if(!appUsersManager.hasUser(update.user_id)) { - if(update.chat_id && - appChatsManager.hasChat(update.chat_id) && - !appChatsManager.isChannel(update.chat_id)) { - appProfileManager.getChatFull(update.chat_id); - } - - //return; - } - - appUsersManager.forceUserOnline(update.user_id); - - let dialog = appMessagesManager.getDialogByPeerID(peerID)[0]; - let currentPeer = this.peerID == peerID; - - if(this.typingTimeouts[peerID]) clearTimeout(this.typingTimeouts[peerID]); - else if(dialog) { - appDialogsManager.setTyping(dialog, appUsersManager.getUser(update.user_id)); - - if(currentPeer) { // user - this.setPeerStatus(); - } - } - - this.typingTimeouts[peerID] = setTimeout(() => { - this.typingTimeouts[peerID] = 0; - delete this.typingUsers[update.user_id]; - - if(dialog) { - appDialogsManager.unsetTyping(dialog); - } - - // лень просчитывать случаи - this.setPeerStatus(); - }, 6000); - break; - } - }) + this.handleUpdate(update); + }); window.addEventListener('blur', () => { lottieLoader.checkAnimations(true); @@ -298,6 +253,9 @@ export class AppImManager { this.setPeer(this.peerID, mid); }); + this.btnMenuMute.addEventListener('click', () => this.mutePeer()); + this.btnMute.addEventListener('click', () => this.mutePeer()); + this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3); this.updateStatus(); setInterval(() => this.setPeerStatus(), 60e3); @@ -524,11 +482,10 @@ export class AppImManager { } } - - public cleanup() { this.peerID = $rootScope.selectedPeerID = 0; this.scrolledAll = false; + this.muted = false; if(this.lastContainerDiv) this.lastContainerDiv.remove(); if(this.firstContainerDiv) this.firstContainerDiv.remove(); @@ -545,6 +502,8 @@ export class AppImManager { this.unreadOut = []; this.loadMediaQueue = []; + lottieLoader.checkAnimations(false, 'chat', true); + console.time('chatInner clear'); this.chatInner.innerHTML = ''; @@ -954,7 +913,7 @@ export class AppImManager { } return true; - }, null, '', false, !!message.pending)/* .then(() => { + }, null, 'chat', false, !!message.pending || !multipleRender)/* .then(() => { attachmentDiv.style.width = ''; attachmentDiv.style.height = ''; @@ -1239,6 +1198,150 @@ export class AppImManager { return true; }); } + + public setMutedState(muted = false) { + appSidebarRight.profileElements.notificationsCheckbox.checked = !muted; + appSidebarRight.profileElements.notificationsStatus.innerText = muted ? 'Disabled' : 'Enabled'; + + let peerID = this.peerID; + + this.muted = muted; + if(peerID < 0) { // not human + let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID); + if(isChannel) { + this.btnMute.classList.remove('tgico-mute', 'tgico-unmute'); + this.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute'); + this.btnMute.style.display = ''; + } else { + this.btnMute.style.display = 'none'; + } + } else { + this.btnMute.style.display = 'none'; + } + + this.btnMenuMute.classList.remove('tgico-mute', 'tgico-unmute'); + this.btnMenuMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute'); + let rp = this.btnMenuMute.firstElementChild; + this.btnMenuMute.innerText = muted ? 'Unmute' : 'Mute'; + this.btnMenuMute.appendChild(rp); + } + + public mutePeer() { + let inputPeer = appPeersManager.getInputPeerByID(this.peerID); + let inputNotifyPeer = { + _: 'inputNotifyPeer', + peer: inputPeer + }; + + let settings: any = { + _: 'inputPeerNotifySettings', + flags: 0, + mute_until: 0 + }; + + if(!this.muted) { + settings.flags |= 2 << 1; + settings.mute_until = 2147483646; + } else { + settings.flags |= 1 << 1; + } + + apiManager.invokeApi('account.updateNotifySettings', { + peer: inputNotifyPeer, + settings: settings + }).then(res => { + this.handleUpdate({_: 'updateNotifySettings', peer: inputNotifyPeer, notify_settings: settings}); + }); + + /* return apiManager.invokeApi('account.getNotifySettings', { + peer: inputNotifyPeer + }).then((settings: any) => { + settings.flags |= 2 << 1; + settings.mute_until = 2000000000; // 2147483646 + + return apiManager.invokeApi('account.updateNotifySettings', { + peer: inputNotifyPeer, + settings: Object.assign(settings, { + _: 'inputPeerNotifySettings' + }) + }).then(res => { + this.log('mute result:', res); + }); + }); */ + + } + + public handleUpdate(update: any) { + switch(update._) { + case 'updateUserTyping': + case 'updateChatUserTyping': + if(this.myID == update.user_id) { + return; + } + + var peerID = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id; + this.typingUsers[update.user_id] = peerID; + + if(!appUsersManager.hasUser(update.user_id)) { + if(update.chat_id && + appChatsManager.hasChat(update.chat_id) && + !appChatsManager.isChannel(update.chat_id)) { + appProfileManager.getChatFull(update.chat_id); + } + + //return; + } + + appUsersManager.forceUserOnline(update.user_id); + + let dialog = appMessagesManager.getDialogByPeerID(peerID)[0]; + let currentPeer = this.peerID == peerID; + + if(this.typingTimeouts[peerID]) clearTimeout(this.typingTimeouts[peerID]); + else if(dialog) { + appDialogsManager.setTyping(dialog, appUsersManager.getUser(update.user_id)); + + if(currentPeer) { // user + this.setPeerStatus(); + } + } + + this.typingTimeouts[peerID] = setTimeout(() => { + this.typingTimeouts[peerID] = 0; + delete this.typingUsers[update.user_id]; + + if(dialog) { + appDialogsManager.unsetTyping(dialog); + } + + // лень просчитывать случаи + this.setPeerStatus(); + }, 6000); + break; + + case 'updateNotifySettings': { + let {peer, notify_settings} = update; + + // peer was NotifyPeer + peer = peer.peer; + + let peerID = appPeersManager.getPeerID(peer); + + let dialog = appMessagesManager.getDialogByPeerID(peerID)[0]; + if(dialog) { + dialog.notify_settings = notify_settings; + } + + if(peerID == this.peerID) { + let muted = notify_settings.mute_until ? new Date(notify_settings.mute_until * 1000) > new Date() : false; + this.setMutedState(muted); + } + + this.log('updateNotifySettings', peerID, notify_settings); + break; + } + } + } } export default new AppImManager(); diff --git a/src/lib/appManagers/appSidebarLeft.ts b/src/lib/appManagers/appSidebarLeft.ts index 447b868d..3e60abf9 100644 --- a/src/lib/appManagers/appSidebarLeft.ts +++ b/src/lib/appManagers/appSidebarLeft.ts @@ -1,5 +1,6 @@ import { logger } from "../polyfill"; -import { scrollable, putPreloader } from "../../components/misc"; +import { putPreloader } from "../../components/misc"; +import Scrollable from '../../components/scrollable'; import appMessagesManager from "./appMessagesManager"; import appDialogsManager from "./appDialogsManager"; import { isElementInViewport } from "../utils"; @@ -20,12 +21,9 @@ class AppSidebarLeft { private chatsContainer = document.getElementById('chats-container') as HTMLDivElement; private chatsOffsetIndex = 0; - private chatsScroll: HTMLDivElement; - private chatsHidden: any; private chatsPreloader: HTMLDivElement; private chatsLoadCount = 0; private loadDialogsPromise: Promise; - private hiddenScroll: any; private log = logger('SL'); @@ -39,6 +37,8 @@ class AppSidebarLeft { private searchTimeout: number = 0; private query = ''; + + public scroll: Scrollable = null; constructor() { this.chatsPreloader = document.createElement('div'); @@ -48,16 +48,13 @@ class AppSidebarLeft { this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5); - let {container: chatsScroll, hiddenElements: chatsHidden, onScroll: hiddenScroll} = scrollable(this.chatsContainer as HTMLDivElement); - this.chatsScroll = chatsScroll; - this.chatsHidden = chatsHidden; - this.hiddenScroll = hiddenScroll; - - appDialogsManager.chatsHidden = this.chatsHidden; + this.scroll = new Scrollable(this.chatsContainer as HTMLDivElement); + appDialogsManager.chatsHidden = this.scroll.hiddenElements; + this.scroll.setVirtualContainer(appDialogsManager.chatList); - chatsScroll.addEventListener('scroll', this.onChatsScroll.bind(this)); + this.scroll.container.addEventListener('scroll', this.onChatsScroll.bind(this)); - this.listsContainer = scrollable(this.searchContainer).container; + this.listsContainer = new Scrollable(this.searchContainer).container; this.searchMessagesList = document.createElement('ul'); this.savedBtn.addEventListener('click', () => { @@ -163,8 +160,8 @@ class AppSidebarLeft { }); } - this.log('loaded ' + this.chatsLoadCount + ' dialogs by offset:', this.chatsOffsetIndex, result, this.chatsHidden); - this.hiddenScroll(); + this.log('loaded ' + this.chatsLoadCount + ' dialogs by offset:', this.chatsOffsetIndex, result, this.scroll.hiddenElements); + this.scroll.onScroll(); } catch(err) { this.log.error(err); } @@ -174,7 +171,8 @@ class AppSidebarLeft { } public onChatsScroll() { - if(this.chatsHidden.down.length > 0/* || 1 == 1 */) return; + //this.log(this.scroll); + if(this.scroll.hiddenElements.down.length > 0/* || 1 == 1 */) return; if(!this.loadDialogsPromise) { let d = Array.from(appDialogsManager.chatList.childNodes).slice(-5); diff --git a/src/lib/appManagers/appSidebarRight.ts b/src/lib/appManagers/appSidebarRight.ts index ba7ec188..bf822348 100644 --- a/src/lib/appManagers/appSidebarRight.ts +++ b/src/lib/appManagers/appSidebarRight.ts @@ -1,4 +1,5 @@ import { LazyLoadQueue, horizontalMenu, wrapDocument, formatPhoneNumber } from "../../components/misc"; +import Scrollable from '../../components/scrollable'; import { isElementInViewport, $rootScope } from "../utils"; import appMessagesManager from "./appMessagesManager"; import appPhotosManager from "./appPhotosManager"; @@ -33,7 +34,7 @@ class AppSidebarRight { contentAudio: this.profileContentEl.querySelector('#content-audio') as HTMLDivElement, }; - public sidebarScroll: HTMLDivElement = null; + public lastSharedMediaDiv: HTMLDivElement = null; private loadSidebarMediaPromises: { [type: string]: Promise @@ -67,13 +68,21 @@ class AppSidebarRight { private peerID = 0; + public sidebarScroll: Scrollable = null; + constructor() { let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement; let tabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement; + this.sidebarScroll = new Scrollable(this.sidebarEl); + this.sidebarScroll.container.addEventListener('scroll', this.onSidebarScroll.bind(this)); + horizontalMenu(tabs, container, (id, tabContent) => { this.sharedMediaType = this.sharedMediaTypes[id]; this.sharedMediaSelected = tabContent.firstElementChild as HTMLDivElement; + + this.log('setVirtualContainer', this.sharedMediaSelected); + this.sidebarScroll.setVirtualContainer(this.sharedMediaSelected); }, this.onSidebarScroll.bind(this)); (tabs.children[1] as HTMLLIElement).click(); // set media @@ -96,6 +105,11 @@ class AppSidebarRight { appMediaViewer.openMedia(message, false); }); + this.profileElements.notificationsCheckbox.addEventListener('change', () => { + let checked = this.profileElements.notificationsCheckbox.checked; + appImManager.mutePeer(); + }); + window.addEventListener('resize', () => { setTimeout(() => this.onSidebarScroll(), 0); }); @@ -104,7 +118,7 @@ class AppSidebarRight { public onSidebarScroll() { this.lazyLoadQueueSidebar.check(); - if(this.sharedMediaSelected) { + if(this.sharedMediaSelected && !this.sidebarScroll.hiddenElements.down.length/* && false */) { let media = Array.from(this.sharedMediaSelected.childNodes).slice(-15); for(let div of media) { if(isElementInViewport(div)) { @@ -117,16 +131,6 @@ class AppSidebarRight { } } - public setScroll(scroll: HTMLDivElement) { - this.sidebarScroll = scroll; - this.sidebarScroll.addEventListener('scroll', this.onSidebarScroll.bind(this)); - /* this.sidebarScroll.options({ - callbacks: { - onScroll: this.onSidebarScroll.bind(this) - } - }); */ - } - public toggleSidebar(enable?: boolean) { this.log('sidebarEl', this.sidebarEl, enable, isElementInViewport(this.sidebarEl)); @@ -239,8 +243,14 @@ class AppSidebarRight { div.setAttribute('message-id', '' + mid); this.lazyLoadQueueSidebar.push({div, load}); + + this.lastSharedMediaDiv.append(div); + if(this.lastSharedMediaDiv.childElementCount == 3) { + this.sharedMedia.contentMedia.append(this.lastSharedMediaDiv); + this.lastSharedMediaDiv = document.createElement('div'); + } - this.sharedMedia.contentMedia.append(div); + //this.sharedMedia.contentMedia.append(div); break; } @@ -285,12 +295,13 @@ class AppSidebarRight { public fillProfileElements() { let peerID = this.peerID = $rootScope.selectedPeerID; this.loadSidebarMediaPromises = {}; + this.lastSharedMediaDiv = document.createElement('div'); this.profileContentEl.parentElement.scrollTop = 0; this.profileElements.bio.style.display = 'none'; this.profileElements.phone.style.display = 'none'; this.profileElements.username.style.display = 'none'; - this.profileElements.notificationsCheckbox.setAttribute('checked', 'checked'); + this.profileElements.notificationsCheckbox.checked = true; this.profileElements.notificationsStatus.innerText = 'Enabled'; Object.keys(this.sharedMedia).forEach(key => { @@ -365,30 +376,9 @@ class AppSidebarRight { let muted = false; if(dialog.notify_settings && dialog.notify_settings.mute_until) { muted = new Date(dialog.notify_settings.mute_until * 1000) > new Date(); - if(muted) { - this.profileElements.notificationsCheckbox.removeAttribute('checked'); - this.profileElements.notificationsStatus.innerText = 'Disabled'; - } - } - - if(peerID < 0) { // not human - let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID); - if(isChannel) { - appImManager.btnMute.classList.remove('tgico-mute', 'tgico-unmute'); - appImManager.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute'); - appImManager.btnMute.style.display = ''; - } else { - appImManager.btnMute.style.display = 'none'; - } - } else { - appImManager.btnMute.style.display = 'none'; } - appImManager.btnMenuMute.classList.remove('tgico-mute', 'tgico-unmute'); - appImManager.btnMenuMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute'); - let rp = appImManager.btnMenuMute.firstElementChild; - appImManager.btnMenuMute.innerText = muted ? 'Unmute' : 'Mute'; - appImManager.btnMenuMute.appendChild(rp); + appImManager.setMutedState(muted); } //this.loadSidebarMedia(); diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts index d15e29f8..2b7e5d92 100644 --- a/src/lib/appManagers/appUsersManager.ts +++ b/src/lib/appManagers/appUsersManager.ts @@ -28,7 +28,7 @@ export class AppUsersManager { $rootScope.$on('apiUpdate', (e: CustomEvent) => { let update = e.detail; - console.log('on apiUpdate', update); + //console.log('on apiUpdate', update); switch(update._) { case 'updateUserStatus': var userID = update.user_id; diff --git a/src/lib/lottieLoader.ts b/src/lib/lottieLoader.ts index c8624326..88b19add 100644 --- a/src/lib/lottieLoader.ts +++ b/src/lib/lottieLoader.ts @@ -2,18 +2,19 @@ import LottiePlayer, { AnimationConfigWithPath, AnimationConfigWithData, Animati import { isElementInViewport, isInDOM } from "./utils"; class LottieLoader { - private lottie: /* any */ typeof LottiePlayer = null; + public lottie: /* any */ typeof LottiePlayer = null; private animations: { [group: string]: { animation: AnimationItem, container: HTMLDivElement, paused: boolean, - autoplay: boolean + autoplay: boolean, + canvas: boolean }[] } = {}; private debug = false; - public checkAnimations(blurred?: boolean, group?: string) { + public checkAnimations(blurred?: boolean, group?: string, destroy = false) { let groups = group ? [group] : Object.keys(this.animations); if(group && !this.animations[group]) { @@ -27,9 +28,17 @@ class LottieLoader { let length = animations.length; for(let i = length - 1; i >= 0; --i) { - let {animation, container, paused, autoplay} = animations[i]; + let {animation, container, paused, autoplay, canvas} = animations[i]; + + if(canvas && isElementInViewport(container)) { + let c = container.firstElementChild as HTMLCanvasElement; + if(!c.height && !c.width) { + console.log('lottie need resize'); + animation.resize(); + } + } - if(!isInDOM(container)) { + if(destroy && !isInDOM(container)) { this.debug && console.log('destroy animation'); animation.destroy(); animations.splice(i, 1); @@ -82,7 +91,8 @@ class LottieLoader { animation, container: params.container as HTMLDivElement, paused: !params.autoplay, - autoplay: params.autoplay + autoplay: params.autoplay, + canvas: params.renderer == 'canvas' }); if(params.autoplay) { diff --git a/src/lib/mtproto/networker.ts b/src/lib/mtproto/networker.ts index fecb3f88..0da74bca 100644 --- a/src/lib/mtproto/networker.ts +++ b/src/lib/mtproto/networker.ts @@ -290,6 +290,10 @@ class MTPNetworker { } options.resultType = serializer.storeMethod(method, params); + + if(method == 'account.updateNotifySettings') { + this.log('api call body:', serializer.getBytes(true)); + } var messageID = timeManager.generateID(); var seqNo = this.generateSeqNo(); diff --git a/src/lib/tl_utils.ts b/src/lib/tl_utils.ts index 67bc535b..8d5223ff 100644 --- a/src/lib/tl_utils.ts +++ b/src/lib/tl_utils.ts @@ -242,6 +242,7 @@ class TLSerialization { var i, condType; var fieldBit; var len = methodData.params.length; + //console.log('storeMethod', len, methodData); for(i = 0; i < len; i++) { param = methodData.params[i]; type = param.type; @@ -339,18 +340,22 @@ class TLSerialization { var condType; var fieldBit; var len = constructorData.params.length; + //console.log('storeObject', len, constructorData); for(i = 0; i < len; i++) { param = constructorData.params[i]; type = param.type; + //console.log('storeObject', param, type); if(type.indexOf('?') !== -1) { condType = type.split('?'); fieldBit = condType[0].split('.'); + //console.log('storeObject fieldBit', fieldBit, obj[fieldBit[0]]); if(!(obj[fieldBit[0]] & (1 << +fieldBit[1]))) { continue; } type = condType[1]; } + //console.log('storeObject', param, type); this.storeObject(obj[param.name], type, field + '[' + predicate + '][' + param.name + ']'); } @@ -707,9 +712,12 @@ class TLDeserialization { fieldBit = condType[0].split('.'); if(!(result[fieldBit[0]] & (1 << fieldBit[1]))) { + //console.log('fetchObject bad', constructorData, result[fieldBit[0]], fieldBit); continue; } + //console.log('fetchObject good', constructorData, result[fieldBit[0]], fieldBit); + type = condType[1]; } diff --git a/src/lib/utils.js b/src/lib/utils.js index b06576aa..2d09d971 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -359,6 +359,35 @@ export function isElementInViewport(el) { return elements.find(e => el.contains(e) || el.parentElement == e) !== undefined; } +export function isScrolledIntoView(el) { + var rect = el.getBoundingClientRect(); + var elemTop = rect.top; + var elemBottom = rect.bottom; + + // Only completely visible elements return true: + //var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight); + // Partially visible elements return true: + var isVisible = elemTop < window.innerHeight && elemBottom >= 0; + return isVisible; +} + +/* export function isScrolledIntoView(el) { + var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height, + el = el.parentNode + // Check if bottom of the element is off the page + if (rect.bottom < 0) return false + // Check its within the document viewport + if (top > document.documentElement.clientHeight) return false + do { + rect = el.getBoundingClientRect() + if (top <= rect.bottom === false) return false + // Check if the element is out of view due to a container scrolling + if ((top + height) <= rect.top) return false + el = el.parentNode + } while (el != document.body) + return true +}; */ + export function whichChild(elem/* : Node */) { let i = 0; // @ts-ignore diff --git a/src/scss/partials/_chatlist.scss b/src/scss/partials/_chatlist.scss index d73a849d..eebd4e87 100644 --- a/src/scss/partials/_chatlist.scss +++ b/src/scss/partials/_chatlist.scss @@ -42,49 +42,61 @@ ul { margin: 0; - padding: 0 .5rem; + //padding: 0 .5rem; + display: grid; + grid-auto-columns: 1fr; + /* grid-gap: 4px; */ } - #dialogs-pinned { - border-bottom: 1px solid #DADCE0; - - &:empty { - display: none; - } + li { + padding: 2px 0; + overflow: hidden; + background-color: #fff; } - li { - padding: 0 .5rem; + li > .rp { height: 70px; max-height: 70px; - overflow: hidden; border-radius: $border-radius; - background-color: #fff; display: grid; align-items: center; grid-template-columns: 60px calc(100% - 60px); position: relative; - /* grid-template-columns: 60px calc(85% - 60px) 15%; */ - cursor: pointer; + padding: 0 .5rem; + margin: 0 .5rem; + overflow: hidden; &:hover { background: rgba(112, 117, 121, .08); } + } - &.active { - background: darken(rgba(112, 117, 121, .1), .8); - } + li.active > .rp { + background: darken(rgba(112, 117, 121, .1), .8); + } + + .pinned-delimiter { + display: flex; + padding: 8px 0 4px; - /* &.dialog-pinned + li:not(.dialog-pinned) { - - } */ + span { + margin: 0; + width: 100%; + height: 1px; + background-color: #DADCE0; + } } + /* li.dialog-pinned + .pinned-delimiter { + display: flex; + } */ + p { margin: 0; display: flex; justify-content: space-between; + align-items: center; height: 1.7rem; // hot-fix span:not(.tgico-pinnedchat):not(.emoji):last-child { @@ -117,9 +129,6 @@ } .user-last-message { - /* display: block; */ - /* display: flex; - align-items: center; */ max-width: 80%; i { @@ -142,16 +151,7 @@ color: $success-color; font-size: 1.15rem; } - } - - /* .dialog-details { - text-align: right; - - :first-child { - font-size: .9rem; - display: block; - } - } */ + } .unread, .unread-muted { border-radius: 12px; diff --git a/src/scss/partials/_sidebar.scss b/src/scss/partials/_sidebar.scss index b0234c9f..f208fe32 100644 --- a/src/scss/partials/_sidebar.scss +++ b/src/scss/partials/_sidebar.scss @@ -121,26 +121,36 @@ } */ #content-media { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - grid-auto-rows: max-content; - grid-gap: 3.5px; - place-items: start; + width: 100%; + display: flex; + flex-direction: column; > div { - width: 100%; - cursor: pointer; - - background-repeat: no-repeat; - background-size: cover; - background-position: center center; - - &::before { - content: ""; - display: inline-block; - width: 1px; - height: 0; - padding-bottom: 100%; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-auto-rows: max-content; + grid-gap: 3.5px; + place-items: start; + + & + div { + margin-top: 3.5px; + } + + > div { + width: 100%; + cursor: pointer; + + background-repeat: no-repeat; + background-size: cover; + background-position: center center; + + &::before { + content: ""; + display: inline-block; + width: 1px; + height: 0; + padding-bottom: 100%; + } } } } diff --git a/src/scss/style.scss b/src/scss/style.scss index ae2269d4..db8d2732 100644 --- a/src/scss/style.scss +++ b/src/scss/style.scss @@ -144,7 +144,7 @@ input { position: absolute; background: #fff; box-shadow: 0 5px 8px 1px rgba(0,0,0,.24); - z-index: 1; + z-index: 3; top: 100%; margin-top: 8px; padding: 9px 0; @@ -1301,6 +1301,7 @@ div.scrollable::-webkit-scrollbar-thumb { &.active { display: flex; + flex-direction: column; } > div {