Private search in RS & search highlight query & sidebar stripe animation
This commit is contained in:
parent
bd0a2bdf39
commit
dd877bee83
236
src/components/appSearch.ts
Normal file
236
src/components/appSearch.ts
Normal file
@ -0,0 +1,236 @@
|
||||
import appDialogsManager from "../lib/appManagers/appDialogsManager";
|
||||
import Scrollable from "./scrollable";
|
||||
import appMessagesIDsManager from "../lib/appManagers/appMessagesIDsManager";
|
||||
import appUsersManager from "../lib/appManagers/appUsersManager";
|
||||
import appPeersManager from '../lib/appManagers/appPeersManager';
|
||||
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||
import { numberWithCommas, escapeRegExp } from "../lib/utils";
|
||||
import { formatPhoneNumber } from "./misc";
|
||||
|
||||
export class SearchGroup {
|
||||
container: HTMLDivElement;
|
||||
nameEl: HTMLDivElement;
|
||||
list: HTMLUListElement;
|
||||
|
||||
constructor(public name: string, public type: string) {
|
||||
this.list = document.createElement('ul');
|
||||
this.container = document.createElement('div');
|
||||
this.nameEl = document.createElement('div');
|
||||
this.nameEl.classList.add('search-group__name');
|
||||
this.nameEl.innerText = name;
|
||||
|
||||
this.container.classList.add('search-group');
|
||||
this.container.append(this.nameEl, this.list);
|
||||
this.container.style.display = 'none';
|
||||
|
||||
appDialogsManager.setListClickListener(this.list);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.container.style.display = 'none';
|
||||
this.list.innerHTML = '';
|
||||
}
|
||||
|
||||
setActive() {
|
||||
this.container.style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
export default class AppSearch {
|
||||
private minMsgID = 0;
|
||||
private loadedCount = 0;
|
||||
private foundCount = 0;
|
||||
private offsetRate = 0;
|
||||
|
||||
private searchPromise: Promise<void> = null;
|
||||
private searchTimeout: number = 0;
|
||||
|
||||
private query = '';
|
||||
|
||||
private listsContainer: HTMLDivElement = null;
|
||||
|
||||
private peerID = 0; // 0 - means global
|
||||
|
||||
private scrollable: Scrollable;
|
||||
|
||||
constructor(public container: HTMLDivElement, public searchInput: HTMLInputElement, public searchGroups: {[group: string]: SearchGroup}) {
|
||||
this.scrollable = new Scrollable(this.container);
|
||||
this.listsContainer = this.scrollable.container;
|
||||
for(let i in this.searchGroups) {
|
||||
this.listsContainer.append(this.searchGroups[i].container);
|
||||
}
|
||||
|
||||
this.searchInput.addEventListener('input', (e) => {
|
||||
let value = this.searchInput.value;
|
||||
if(!value.trim()) {
|
||||
//this.peerID = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
this.query = value;
|
||||
this.reset(false);
|
||||
this.searchMore();
|
||||
});
|
||||
|
||||
this.scrollable.onScrolledBottom = () => {
|
||||
if(!this.query.trim()) return;
|
||||
|
||||
if(!this.searchTimeout) {
|
||||
this.searchTimeout = setTimeout(() => {
|
||||
this.searchMore();
|
||||
this.searchTimeout = 0;
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public reset(all = true) {
|
||||
if(all) {
|
||||
this.searchInput.value = '';
|
||||
this.query = '';
|
||||
this.peerID = 0;
|
||||
}
|
||||
|
||||
this.minMsgID = 0;
|
||||
this.loadedCount = 0;
|
||||
this.foundCount = 0;
|
||||
this.offsetRate = 0;
|
||||
|
||||
for(let i in this.searchGroups) {
|
||||
this.searchGroups[i].clear();
|
||||
}
|
||||
|
||||
this.searchPromise = null;
|
||||
}
|
||||
|
||||
public beginSearch(peerID?: number) {
|
||||
if(peerID) {
|
||||
this.peerID = peerID;
|
||||
}
|
||||
|
||||
this.searchInput.focus();
|
||||
}
|
||||
|
||||
private searchMore() {
|
||||
if(this.searchPromise) return this.searchPromise;
|
||||
|
||||
let query = this.query;
|
||||
|
||||
if(!query.trim()) return;
|
||||
|
||||
if(this.loadedCount != 0 && this.loadedCount >= this.foundCount) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let maxID = appMessagesIDsManager.getMessageIDInfo(this.minMsgID)[0];
|
||||
|
||||
if(!this.peerID && !maxID) {
|
||||
appUsersManager.searchContacts(query, 20).then((contacts: any) => {
|
||||
if(this.searchInput.value != query) {
|
||||
return;
|
||||
}
|
||||
|
||||
///////this.log('input search contacts result:', contacts);
|
||||
|
||||
let setResults = (results: any, group: SearchGroup, showMembersCount = false) => {
|
||||
results.forEach((inputPeer: any) => {
|
||||
let peerID = appPeersManager.getPeerID(inputPeer);
|
||||
let peer = appPeersManager.getPeer(peerID);
|
||||
let originalDialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
||||
|
||||
//////////this.log('contacts peer', peer);
|
||||
|
||||
if(!originalDialog) {
|
||||
/////////this.log('no original dialog by peerID:', peerID);
|
||||
|
||||
originalDialog = {
|
||||
peerID: peerID,
|
||||
pFlags: {},
|
||||
peer: peer
|
||||
};
|
||||
}
|
||||
|
||||
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, group.list, false);
|
||||
|
||||
if(showMembersCount && (peer.participants_count || peer.participants)) {
|
||||
let regExp = new RegExp(`(${escapeRegExp(query)})`, 'gi');
|
||||
dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');
|
||||
|
||||
let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
|
||||
let participants_count = peer.participants_count || peer.participants.participants.length;
|
||||
let subtitle = numberWithCommas(participants_count) + ' ' + (isChannel ? 'subscribers' : 'members');
|
||||
dom.lastMessageSpan.innerText = subtitle;
|
||||
} else {
|
||||
let username = appPeersManager.getPeerUsername(peerID);
|
||||
if(!username) {
|
||||
let user = appUsersManager.getUser(peerID);
|
||||
if(user && user.phone) {
|
||||
username = '+' + formatPhoneNumber(user.phone).formatted;
|
||||
}
|
||||
} else {
|
||||
username = '@' + username;
|
||||
}
|
||||
|
||||
dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';
|
||||
}
|
||||
});
|
||||
|
||||
if(results.length) {
|
||||
group.setActive();
|
||||
}
|
||||
};
|
||||
|
||||
setResults(contacts.my_results, this.searchGroups.contacts, true);
|
||||
setResults(contacts.results, this.searchGroups.globalContacts);
|
||||
});
|
||||
}
|
||||
|
||||
return this.searchPromise = appMessagesManager.getSearch(this.peerID, query, null, maxID, 20, this.offsetRate).then(res => {
|
||||
this.searchPromise = null;
|
||||
|
||||
if(this.searchInput.value != query) {
|
||||
return;
|
||||
}
|
||||
|
||||
/////////this.log('input search result:', this.peerID, query, null, maxID, 20, res);
|
||||
|
||||
let {count, history, next_rate} = res;
|
||||
|
||||
if(history[0] == this.minMsgID) {
|
||||
history.shift();
|
||||
}
|
||||
|
||||
let searchGroup = this.searchGroups['messages'];
|
||||
searchGroup.setActive();
|
||||
|
||||
history.forEach((msgID: number) => {
|
||||
let message = appMessagesManager.getMessage(msgID);
|
||||
let originalDialog = appMessagesManager.getDialogByPeerID(message.peerID)[0];
|
||||
|
||||
if(!originalDialog) {
|
||||
////////this.log('no original dialog by message:', message);
|
||||
|
||||
originalDialog = {
|
||||
peerID: message.peerID,
|
||||
pFlags: {},
|
||||
peer: message.to_id
|
||||
};
|
||||
}
|
||||
|
||||
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, searchGroup.list, false);
|
||||
appDialogsManager.setLastMessage(dialog, message, dom, query);
|
||||
});
|
||||
|
||||
this.minMsgID = history[history.length - 1];
|
||||
this.offsetRate = next_rate;
|
||||
this.loadedCount += history.length;
|
||||
|
||||
if(!this.foundCount) {
|
||||
this.foundCount = count;
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('search error', err);
|
||||
this.searchPromise = null;
|
||||
});
|
||||
}
|
||||
}
|
@ -34,7 +34,9 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||
lazyLoadQueue.check(); // for stickers
|
||||
});
|
||||
(tabs.children[0] as HTMLLIElement).click(); // set media
|
||||
|
||||
(tabs.firstElementChild.children[0] as HTMLLIElement).click(); // set emoji tab
|
||||
(tabs.lastElementChild as HTMLSpanElement).style.cssText = 'width: 44.1719px; transform: translateX(88.5781px);'; // мы снова встретились))))))
|
||||
|
||||
let emoticonsMenuOnClick = (menu: HTMLUListElement, heights: number[], scroll: Scrollable, menuScroll?: Scrollable) => {
|
||||
menu.addEventListener('click', function(e) {
|
||||
@ -151,7 +153,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
let heights: number[] = [0];
|
||||
|
||||
let prevCategoryIndex = 1;
|
||||
let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement;
|
||||
let menu = contentEmojiDiv.nextElementSibling.firstElementChild as HTMLUListElement;
|
||||
let emojiScroll = new Scrollable(contentEmojiDiv, 'y', 500, 'EMOJI', null);
|
||||
emojiScroll.container.addEventListener('scroll', (e) => {
|
||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll.container);
|
||||
@ -205,7 +207,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
//let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;
|
||||
|
||||
let menuWrapper = contentStickersDiv.nextElementSibling as HTMLDivElement;
|
||||
let menu = menuWrapper.firstElementChild as HTMLUListElement;
|
||||
let menu = menuWrapper.firstElementChild.firstElementChild as HTMLUListElement;
|
||||
|
||||
let menuScroll = new Scrollable(menuWrapper, 'x');
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { whichChild, findUpTag, cancelEvent } from "../lib/utils";
|
||||
import { whichChild, findUpTag } from "../lib/utils";
|
||||
|
||||
let rippleClickID = 0;
|
||||
export function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null) {
|
||||
@ -141,13 +141,13 @@ export function putPreloader(elem: Element, returnDiv = false) {
|
||||
elem.innerHTML += html;
|
||||
}
|
||||
|
||||
export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void, transitionTime = 300) {
|
||||
export function horizontalMenu(tabs: HTMLElement, content: HTMLDivElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void, transitionTime = 300) {
|
||||
let hideTimeout: number = 0;
|
||||
let prevTabContent: HTMLDivElement = null;
|
||||
|
||||
let prevId = -1;
|
||||
let children = Array.from(content.children);
|
||||
let tabsChildren = tabs ? Array.from(tabs.children) : [];
|
||||
let tabsChildren = tabs ? Array.from(tabs.firstElementChild.children) : [];
|
||||
let activeInSlide: Set<Element> = new Set();
|
||||
|
||||
let selectTab = (id: number) => {
|
||||
@ -227,6 +227,11 @@ export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement,
|
||||
};
|
||||
|
||||
if(tabs) {
|
||||
let activeStripe = document.createElement('span');
|
||||
activeStripe.classList.add('menu-horizontal__stripe');
|
||||
|
||||
tabs.append(activeStripe);
|
||||
|
||||
tabs.addEventListener('click', function(e) {
|
||||
let target = e.target as HTMLLIElement;
|
||||
|
||||
@ -242,7 +247,6 @@ export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement,
|
||||
let tabContent = content.children[id] as HTMLDivElement;
|
||||
|
||||
if(activeInSlide.size >= 2 && !activeInSlide.has(tabContent)) {
|
||||
cancelEvent(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -253,7 +257,13 @@ export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement,
|
||||
|
||||
let prev = tabs.querySelector('li.active') as HTMLLIElement;
|
||||
prev && prev.classList.remove('active');
|
||||
|
||||
|
||||
let tabsRect = tabs.getBoundingClientRect();
|
||||
let textRect = target.firstElementChild.getBoundingClientRect();
|
||||
activeStripe.style.cssText = `width: ${textRect.width + (2 * 2)}px; transform: translateX(${textRect.left - tabsRect.left}px);`;
|
||||
//activeStripe.style.transform = `scaleX(${textRect.width}) translateX(${(textRect.left - tabsRect.left) / textRect.width + 0.5}px)`;
|
||||
console.log('tabs click:', tabsRect, textRect);
|
||||
|
||||
target.classList.add('active');
|
||||
selectTab(id);
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { langPack, findUpClassName, $rootScope } from "../utils";
|
||||
import { langPack, findUpClassName, $rootScope, escapeRegExp } from "../utils";
|
||||
import appImManager, { AppImManager } from "./appImManager";
|
||||
import appPeersManager from './appPeersManager';
|
||||
import appMessagesManager, { AppMessagesManager } from "./appMessagesManager";
|
||||
@ -420,7 +420,7 @@ export class AppDialogsManager {
|
||||
chatsHidden.down = inBottom;
|
||||
}
|
||||
|
||||
public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom) {
|
||||
public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom, highlightWord?: string) {
|
||||
if(!lastMessage) {
|
||||
lastMessage = appMessagesManager.getMessage(dialog.top_message);
|
||||
}
|
||||
@ -497,12 +497,58 @@ export class AppDialogsManager {
|
||||
}
|
||||
|
||||
if(lastMessage.action) {
|
||||
let action = lastMessage.action;
|
||||
|
||||
console.log('lastMessage action:', action);
|
||||
|
||||
let suffix = '';
|
||||
let _ = action._;
|
||||
if(_ == "messageActionPhoneCall") {
|
||||
_ += '.' + action.type;
|
||||
|
||||
let duration = action.duration;
|
||||
if(duration) {
|
||||
let d = [];
|
||||
|
||||
d.push(duration % 60 + ' s');
|
||||
if(duration > 60) d.push((duration / 60 | 0) + ' min');
|
||||
if(duration > 3600) d.push((duration / 3600 | 0) + ' h');
|
||||
suffix = ' (' + d.reverse().join(' ') + ')';
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
lastMessageText = langPack[lastMessage.action._];
|
||||
lastMessageText = '<i>' + langPack[_] + suffix + '</i>';
|
||||
}
|
||||
|
||||
dom.lastMessageSpan.innerHTML = lastMessageText +
|
||||
(lastMessage.message ? RichTextProcessor.wrapRichText(lastMessage.message.replace(/\n/g, ' '), {noLinebreakers: true}) : '');
|
||||
|
||||
let messageText = lastMessage.message;
|
||||
let messageWrapped = '';
|
||||
if(messageText) {
|
||||
let entities = RichTextProcessor.parseEntities(messageText, {noLinebreakers: true});
|
||||
if(highlightWord) {
|
||||
let regExp = new RegExp(escapeRegExp(highlightWord), 'gi');
|
||||
let match: any;
|
||||
|
||||
if(!entities) entities = [];
|
||||
let found = false;
|
||||
while((match = regExp.exec(messageText)) !== null) {
|
||||
entities.push({_: 'messageEntityHighlight', length: highlightWord.length, offset: match.index});
|
||||
found = true;
|
||||
}
|
||||
|
||||
if(found) {
|
||||
entities.sort((a: any, b: any) => a.offset - b.offset);
|
||||
}
|
||||
}
|
||||
|
||||
messageWrapped = RichTextProcessor.wrapRichText(messageText.replace(/\n/g, ' '), {
|
||||
noLinebreakers: true,
|
||||
entities: entities,
|
||||
noTextFormat: true
|
||||
});
|
||||
}
|
||||
|
||||
dom.lastMessageSpan.innerHTML = lastMessageText + messageWrapped;
|
||||
|
||||
/* if(lastMessage.from_id == auth.id) { // You: */
|
||||
if(peer._ != 'peerUser' && peerID != -lastMessage.from_id) {
|
||||
|
@ -26,6 +26,8 @@ import LazyLoadQueue from '../../components/lazyLoadQueue';
|
||||
|
||||
console.log('appImManager included!');
|
||||
|
||||
appSidebarLeft; // just to include
|
||||
|
||||
let testScroll = false;
|
||||
|
||||
export class AppImManager {
|
||||
@ -343,7 +345,7 @@ export class AppImManager {
|
||||
}
|
||||
|
||||
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => {
|
||||
if(!this.scrollable.visibleElements.find(e => e.element == this.bubbles[id])) return false;
|
||||
//if(!this.scrollable.visibleElements.find(e => e.element == this.bubbles[id])) return false;
|
||||
|
||||
let message = appMessagesManager.getMessage(id);
|
||||
|
||||
@ -370,7 +372,9 @@ export class AppImManager {
|
||||
|
||||
this.searchBtn.addEventListener('click', (e) => {
|
||||
if(this.peerID) {
|
||||
appSidebarLeft.beginSearch(this.peerID);
|
||||
appSidebarRight.beginSearch();
|
||||
//appSidebarLeft.archivedCount;
|
||||
//appSidebarLeft.beginSearch(this.peerID);
|
||||
}
|
||||
});
|
||||
|
||||
@ -912,6 +916,8 @@ export class AppImManager {
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
appSidebarRight.searchCloseBtn.click();
|
||||
}
|
||||
|
||||
// clear
|
||||
|
@ -1,87 +1,32 @@
|
||||
import { logger } from "../polyfill";
|
||||
import { formatPhoneNumber } from "../../components/misc";
|
||||
import Scrollable from '../../components/scrollable';
|
||||
import appMessagesManager from "./appMessagesManager";
|
||||
//import { logger } from "../polyfill";
|
||||
import appDialogsManager from "./appDialogsManager";
|
||||
import { isElementInViewport, numberWithCommas, $rootScope } from "../utils";
|
||||
import appMessagesIDsManager from "./appMessagesIDsManager";
|
||||
import { $rootScope } from "../utils";
|
||||
import appImManager from "./appImManager";
|
||||
import appUsersManager from "./appUsersManager";
|
||||
import apiManager from "../mtproto/apiManager";
|
||||
import appPeersManager from './appPeersManager';
|
||||
|
||||
class SearchGroup {
|
||||
container: HTMLDivElement;
|
||||
nameEl: HTMLDivElement;
|
||||
list: HTMLUListElement;
|
||||
|
||||
constructor(public name: string, public type: string) {
|
||||
this.list = document.createElement('ul');
|
||||
this.container = document.createElement('div');
|
||||
this.nameEl = document.createElement('div');
|
||||
this.nameEl.classList.add('search-group__name');
|
||||
this.nameEl.innerText = name;
|
||||
|
||||
this.container.classList.add('search-group');
|
||||
this.container.append(this.nameEl, this.list);
|
||||
this.container.style.display = 'none';
|
||||
|
||||
appDialogsManager.setListClickListener(this.list);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.container.style.display = 'none';
|
||||
this.list.innerHTML = '';
|
||||
}
|
||||
|
||||
setActive() {
|
||||
this.container.style.display = '';
|
||||
}
|
||||
}
|
||||
import AppSearch, { SearchGroup } from "../../components/appSearch";
|
||||
|
||||
class AppSidebarLeft {
|
||||
private sidebarEl = document.querySelector('.page-chats .chats-container') as HTMLDivElement;
|
||||
private searchInput = document.getElementById('global-search') as HTMLInputElement;
|
||||
private sidebarEl = document.getElementById('column-left') as HTMLDivElement;
|
||||
private toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;
|
||||
private backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;
|
||||
private searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;
|
||||
private searchInput = document.getElementById('global-search') as HTMLInputElement;
|
||||
|
||||
private menuEl = this.toolsBtn.querySelector('.btn-menu');
|
||||
private savedBtn = this.menuEl.querySelector('.menu-saved');
|
||||
private archivedBtn = this.menuEl.querySelector('.menu-archive');
|
||||
private logOutBtn = this.menuEl.querySelector('.menu-logout');
|
||||
public archivedCount = this.archivedBtn.querySelector('.archived-count') as HTMLSpanElement;
|
||||
|
||||
private listsContainer: HTMLDivElement = null;
|
||||
|
||||
private log = logger('SL');
|
||||
|
||||
private peerID = 0;
|
||||
private minMsgID = 0;
|
||||
private loadedCount = 0;
|
||||
private foundCount = 0;
|
||||
private offsetRate = 0;
|
||||
|
||||
private searchPromise: Promise<void> = null;
|
||||
private searchTimeout: number = 0;
|
||||
|
||||
private query = '';
|
||||
|
||||
public searchGroups: {[group: string]: SearchGroup} = {};
|
||||
//private log = logger('SL');
|
||||
|
||||
private globalSearch = new AppSearch(this.searchContainer, this.searchInput, {
|
||||
contacts: new SearchGroup('Contacts and Chats', 'contacts'),
|
||||
globalContacts: new SearchGroup('Global Search', 'contacts'),
|
||||
messages: new SearchGroup('Global Search', 'messages')
|
||||
});
|
||||
|
||||
constructor() {
|
||||
this.searchGroups = {
|
||||
contacts: new SearchGroup('Contacts and Chats', 'contacts'),
|
||||
globalContacts: new SearchGroup('Global Search', 'contacts'),
|
||||
globalMessages: new SearchGroup('Global Search', 'messages'),
|
||||
privateMessages: new SearchGroup('Private Search', 'messages')
|
||||
};
|
||||
|
||||
this.listsContainer = new Scrollable(this.searchContainer).container;
|
||||
for(let i in this.searchGroups) {
|
||||
this.listsContainer.append(this.searchGroups[i].container);
|
||||
}
|
||||
|
||||
this.savedBtn.addEventListener('click', (e) => {
|
||||
///////this.log('savedbtn click');
|
||||
setTimeout(() => { // menu doesn't close if no timeout (lol)
|
||||
@ -101,19 +46,17 @@ class AppSidebarLeft {
|
||||
this.logOutBtn.addEventListener('click', (e) => {
|
||||
apiManager.logOut();
|
||||
});
|
||||
|
||||
this.listsContainer.addEventListener('scroll', this.onSidebarScroll.bind(this));
|
||||
|
||||
this.searchInput.addEventListener('focus', (e) => {
|
||||
this.toolsBtn.classList.remove('active');
|
||||
this.backBtn.classList.add('active');
|
||||
this.searchContainer.classList.add('active');
|
||||
|
||||
if(!this.searchInput.value) {
|
||||
for(let i in this.searchGroups) {
|
||||
this.searchGroups[i].clear();
|
||||
/* if(!this.globalSearch.searchInput.value) {
|
||||
for(let i in this.globalSearch.searchGroups) {
|
||||
this.globalSearch.searchGroups[i].clear();
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
this.searchInput.addEventListener('blur', (e) => {
|
||||
if(!this.searchInput.value) {
|
||||
@ -128,46 +71,13 @@ class AppSidebarLeft {
|
||||
this.minMsgID = 0; */
|
||||
}, {once: true});
|
||||
});
|
||||
|
||||
this.searchInput.addEventListener('input', (e) => {
|
||||
//console.log('messageInput input', this.innerText, serializeNodes(Array.from(messageInput.childNodes)));
|
||||
let value = this.searchInput.value;
|
||||
////////this.log('input', value);
|
||||
|
||||
if(!value.trim()) {
|
||||
//this.peerID = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
this.query = value;
|
||||
this.minMsgID = 0;
|
||||
this.loadedCount = 0;
|
||||
this.foundCount = 0;
|
||||
this.offsetRate = 0;
|
||||
|
||||
for(let i in this.searchGroups) {
|
||||
this.searchGroups[i].clear();
|
||||
}
|
||||
|
||||
this.searchPromise = null;
|
||||
this.searchMore();
|
||||
});
|
||||
|
||||
this.backBtn.addEventListener('click', (e) => {
|
||||
appDialogsManager.chatsArchivedContainer.classList.remove('active');
|
||||
this.toolsBtn.classList.add('active');
|
||||
this.backBtn.classList.remove('active');
|
||||
this.searchInput.value = '';
|
||||
this.searchContainer.classList.remove('active');
|
||||
this.peerID = 0;
|
||||
});
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
//this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5);
|
||||
|
||||
setTimeout(() => {
|
||||
this.onSidebarScroll();
|
||||
}, 0);
|
||||
this.globalSearch.reset();
|
||||
});
|
||||
|
||||
$rootScope.$on('dialogs_archived_unread', (e: CustomEvent) => {
|
||||
@ -178,154 +88,6 @@ class AppSidebarLeft {
|
||||
this.log('got top categories:', categories);
|
||||
}); */
|
||||
}
|
||||
|
||||
public onSidebarScroll() {
|
||||
if(!this.query.trim()) return;
|
||||
|
||||
let elements = Array.from(this.searchGroups[this.peerID ? 'privateMessages' : 'globalMessages'].list.childNodes).slice(-5);
|
||||
for(let li of elements) {
|
||||
if(isElementInViewport(li)) {
|
||||
this.log('Will load more search');
|
||||
|
||||
if(!this.searchTimeout) {
|
||||
this.searchTimeout = setTimeout(() => {
|
||||
this.searchMore();
|
||||
this.searchTimeout = 0;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public beginSearch(peerID?: number) {
|
||||
if(peerID) {
|
||||
this.peerID = peerID;
|
||||
}
|
||||
|
||||
this.searchInput.focus();
|
||||
}
|
||||
|
||||
private searchMore() {
|
||||
if(this.searchPromise) return this.searchPromise;
|
||||
|
||||
let query = this.query;
|
||||
|
||||
if(!query.trim()) return;
|
||||
|
||||
if(this.loadedCount != 0 && this.loadedCount >= this.foundCount) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let maxID = appMessagesIDsManager.getMessageIDInfo(this.minMsgID)[0];
|
||||
|
||||
if(!this.peerID && !maxID) {
|
||||
appUsersManager.searchContacts(query, 20).then((contacts: any) => {
|
||||
if(this.searchInput.value != query) {
|
||||
return;
|
||||
}
|
||||
|
||||
///////this.log('input search contacts result:', contacts);
|
||||
|
||||
let setResults = (results: any, group: SearchGroup, showMembersCount = false) => {
|
||||
results.forEach((inputPeer: any) => {
|
||||
let peerID = appPeersManager.getPeerID(inputPeer);
|
||||
let peer = appPeersManager.getPeer(peerID);
|
||||
let originalDialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
||||
|
||||
//////////this.log('contacts peer', peer);
|
||||
|
||||
if(!originalDialog) {
|
||||
/////////this.log('no original dialog by peerID:', peerID);
|
||||
|
||||
originalDialog = {
|
||||
peerID: peerID,
|
||||
pFlags: {},
|
||||
peer: peer
|
||||
};
|
||||
}
|
||||
|
||||
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, group.list, false);
|
||||
|
||||
if(showMembersCount && (peer.participants_count || peer.participants)) {
|
||||
let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
|
||||
let participants_count = peer.participants_count || peer.participants.participants.length;
|
||||
let subtitle = numberWithCommas(participants_count) + ' ' + (isChannel ? 'subscribers' : 'members');
|
||||
dom.lastMessageSpan.innerText = subtitle;
|
||||
} else {
|
||||
let username = appPeersManager.getPeerUsername(peerID);
|
||||
if(!username) {
|
||||
let user = appUsersManager.getUser(peerID);
|
||||
if(user && user.phone) {
|
||||
username = '+' + formatPhoneNumber(user.phone).formatted;
|
||||
}
|
||||
} else {
|
||||
username = '@' + username;
|
||||
}
|
||||
|
||||
dom.lastMessageSpan.innerText = username;
|
||||
}
|
||||
});
|
||||
|
||||
if(results.length) {
|
||||
group.setActive();
|
||||
}
|
||||
};
|
||||
|
||||
setResults(contacts.my_results, this.searchGroups.contacts, true);
|
||||
setResults(contacts.results, this.searchGroups.globalContacts);
|
||||
});
|
||||
}
|
||||
|
||||
return this.searchPromise = appMessagesManager.getSearch(this.peerID, query, null, maxID, 20, this.offsetRate).then(res => {
|
||||
this.searchPromise = null;
|
||||
|
||||
if(this.searchInput.value != query) {
|
||||
return;
|
||||
}
|
||||
|
||||
/////////this.log('input search result:', this.peerID, query, null, maxID, 20, res);
|
||||
|
||||
let {count, history, next_rate} = res;
|
||||
|
||||
if(history[0] == this.minMsgID) {
|
||||
history.shift();
|
||||
}
|
||||
|
||||
let searchGroup = this.searchGroups[this.peerID ? 'privateMessages' : 'globalMessages'];
|
||||
searchGroup.setActive();
|
||||
|
||||
history.forEach((msgID: number) => {
|
||||
let message = appMessagesManager.getMessage(msgID);
|
||||
let originalDialog = appMessagesManager.getDialogByPeerID(message.peerID)[0];
|
||||
|
||||
if(!originalDialog) {
|
||||
////////this.log('no original dialog by message:', message);
|
||||
|
||||
originalDialog = {
|
||||
peerID: message.peerID,
|
||||
pFlags: {},
|
||||
peer: message.to_id
|
||||
};
|
||||
}
|
||||
|
||||
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, searchGroup.list, false);
|
||||
appDialogsManager.setLastMessage(dialog, message, dom);
|
||||
});
|
||||
|
||||
this.minMsgID = history[history.length - 1];
|
||||
this.offsetRate = next_rate;
|
||||
this.loadedCount += history.length;
|
||||
|
||||
if(!this.foundCount) {
|
||||
this.foundCount = count;
|
||||
}
|
||||
}).catch(err => {
|
||||
this.log.error('search error', err);
|
||||
this.searchPromise = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const appSidebarLeft = new AppSidebarLeft();
|
||||
|
@ -12,12 +12,14 @@ import appImManager from "./appImManager";
|
||||
import appMediaViewer from "./appMediaViewer";
|
||||
import LazyLoadQueue from "../../components/lazyLoadQueue";
|
||||
import { wrapDocument, wrapAudio } from "../../components/wrappers";
|
||||
import AppSearch, { SearchGroup } from "../../components/appSearch";
|
||||
|
||||
const testScroll = false;
|
||||
|
||||
class AppSidebarRight {
|
||||
public sidebarEl = document.querySelector('.profile-container') as HTMLDivElement;
|
||||
public profileContentEl = document.querySelector('.profile-content') as HTMLDivElement;
|
||||
public sidebarEl = document.getElementById('column-right') as HTMLDivElement;
|
||||
public profileContainer = this.sidebarEl.querySelector('.profile-container') as HTMLDivElement;
|
||||
public profileContentEl = this.sidebarEl.querySelector('.profile-content') as HTMLDivElement;
|
||||
public profileElements = {
|
||||
avatar: this.profileContentEl.querySelector('.profile-avatar') as HTMLDivElement,
|
||||
name: this.profileContentEl.querySelector('.profile-name') as HTMLDivElement,
|
||||
@ -88,12 +90,19 @@ class AppSidebarRight {
|
||||
} = {};
|
||||
|
||||
public urlsToRevoke: string[] = [];
|
||||
|
||||
private searchContainer = this.sidebarEl.querySelector('#search-private-container') as HTMLDivElement;
|
||||
public searchCloseBtn = this.searchContainer.querySelector('.sidebar-close-button') as HTMLButtonElement;
|
||||
private searchInput = document.getElementById('private-search') as HTMLInputElement;
|
||||
public privateSearch = new AppSearch(this.searchContainer.querySelector('.chats-container') as HTMLDivElement, this.searchInput, {
|
||||
messages: new SearchGroup('Private Search', 'messages')
|
||||
});
|
||||
|
||||
constructor() {
|
||||
let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement;
|
||||
this.profileTabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement;
|
||||
|
||||
this.scroll = new Scrollable(this.sidebarEl, 'y', 1200, 'SR');
|
||||
this.scroll = new Scrollable(this.profileContainer, 'y', 1200, 'SR');
|
||||
this.scroll.container.addEventListener('scroll', this.onSidebarScroll.bind(this));
|
||||
this.scroll.onScrolledBottom = () => {
|
||||
if(this.sharedMediaSelected && !this.scroll.hiddenElements.down.length && this.sharedMediaSelected.childElementCount/* && false */) {
|
||||
@ -131,6 +140,11 @@ class AppSidebarRight {
|
||||
sidebarCloseBtn.addEventListener('click', () => {
|
||||
this.toggleSidebar(false);
|
||||
});
|
||||
|
||||
this.searchCloseBtn.addEventListener('click', () => {
|
||||
this.searchContainer.classList.remove('active');
|
||||
this.privateSearch.reset();
|
||||
});
|
||||
|
||||
this.sharedMedia.contentMedia.addEventListener('click', (e) => {
|
||||
let target = e.target as HTMLDivElement;
|
||||
@ -175,6 +189,12 @@ class AppSidebarRight {
|
||||
(this.profileTabs.children[1] as HTMLLIElement).click(); // set media
|
||||
}
|
||||
}
|
||||
|
||||
public beginSearch() {
|
||||
this.toggleSidebar(true);
|
||||
this.searchContainer.classList.add('active');
|
||||
this.privateSearch.beginSearch(this.peerID);
|
||||
}
|
||||
|
||||
public onSidebarScroll() {
|
||||
this.lazyLoadQueueSidebar.check();
|
||||
@ -191,12 +211,8 @@ class AppSidebarRight {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.sidebarEl.classList.contains('active')) {
|
||||
this.sidebarEl.classList.remove('active');
|
||||
} else {
|
||||
this.sidebarEl.classList.add('active');
|
||||
}
|
||||
|
||||
this.sidebarEl.classList.toggle('active');
|
||||
}
|
||||
|
||||
public performSearchResult(ids: number[], type: string) {
|
||||
@ -533,7 +549,7 @@ class AppSidebarRight {
|
||||
this.savedVirtualStates = {};
|
||||
this.prevTabID = -1;
|
||||
this.scroll.setVirtualContainer(null);
|
||||
(this.profileTabs.children[1] as HTMLLIElement).click(); // set media
|
||||
(this.profileTabs.firstElementChild.children[1] as HTMLLIElement).click(); // set media
|
||||
|
||||
//this.scroll.getScrollTopOffset();
|
||||
|
||||
|
@ -547,6 +547,11 @@ function wrapRichText (text, options = {}) {
|
||||
)
|
||||
break
|
||||
case 'messageEntityBold':
|
||||
if(options.noTextFormat) {
|
||||
html.push(wrapRichNestedText(entityText, entity.nested, options));
|
||||
break;
|
||||
}
|
||||
|
||||
html.push(
|
||||
'<strong>',
|
||||
wrapRichNestedText(entityText, entity.nested, options),
|
||||
@ -554,13 +559,30 @@ function wrapRichText (text, options = {}) {
|
||||
)
|
||||
break
|
||||
case 'messageEntityItalic':
|
||||
if(options.noTextFormat) {
|
||||
html.push(wrapRichNestedText(entityText, entity.nested, options));
|
||||
break;
|
||||
}
|
||||
|
||||
html.push(
|
||||
'<em>',
|
||||
wrapRichNestedText(entityText, entity.nested, options),
|
||||
'</em>'
|
||||
)
|
||||
break
|
||||
case 'messageEntityHighlight':
|
||||
html.push(
|
||||
'<i>',
|
||||
wrapRichNestedText(entityText, entity.nested, options),
|
||||
'</i>'
|
||||
)
|
||||
break;
|
||||
case 'messageEntityCode':
|
||||
if(options.noTextFormat) {
|
||||
html.push(encodeEntities(entityText));
|
||||
break;
|
||||
}
|
||||
|
||||
html.push(
|
||||
'<code>',
|
||||
encodeEntities(entityText),
|
||||
@ -568,6 +590,11 @@ function wrapRichText (text, options = {}) {
|
||||
)
|
||||
break
|
||||
case 'messageEntityPre':
|
||||
if(options.noTextFormat) {
|
||||
html.push(encodeEntities(entityText));
|
||||
break;
|
||||
}
|
||||
|
||||
html.push(
|
||||
'<pre><code', (entity.language ? ' class="language-' + encodeEntities(entity.language) + '"' : ''), '>',
|
||||
encodeEntities(entityText),
|
||||
|
@ -615,6 +615,13 @@ export function listUniqSorted (list) {
|
||||
return resultList
|
||||
}
|
||||
|
||||
// credits to https://github.com/sindresorhus/escape-string-regexp/blob/master/index.js
|
||||
export function escapeRegExp(str) {
|
||||
return str
|
||||
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
|
||||
.replace(/-/g, '\\x2d');
|
||||
}
|
||||
|
||||
export function encodeEntities (value) {
|
||||
return value.replace(/&/g, '&').replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, function (value) {
|
||||
var hi = value.charCodeAt(0)
|
||||
|
@ -1,4 +1,6 @@
|
||||
.chats-container {
|
||||
position: relative;
|
||||
|
||||
.input-search {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
@ -155,8 +157,6 @@
|
||||
}
|
||||
|
||||
.user-title {
|
||||
max-width: 80%;
|
||||
|
||||
img.emoji {
|
||||
vertical-align: top;
|
||||
width: 18px;
|
||||
@ -174,13 +174,6 @@
|
||||
}
|
||||
|
||||
.user-last-message {
|
||||
max-width: 80%;
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
color: $darkblue;
|
||||
}
|
||||
|
||||
img.emoji {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
@ -194,6 +187,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.user-title, .user-last-message {
|
||||
max-width: 80%;
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
color: $darkblue;
|
||||
}
|
||||
}
|
||||
|
||||
.message-status {
|
||||
margin-right: .1rem;
|
||||
//margin-top: .3rem;
|
||||
@ -241,4 +243,17 @@
|
||||
.unread-muted, .tgico-pinnedchat {
|
||||
background: #c5c9cc;
|
||||
}
|
||||
|
||||
.search-group {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #DADCE0;
|
||||
padding: 1rem 0 .5rem;
|
||||
margin-bottom: .5rem;
|
||||
|
||||
&__name {
|
||||
color: $color-gray;
|
||||
padding: 0 1.85rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +195,7 @@
|
||||
}
|
||||
|
||||
.emoji-padding, .stickers-padding {
|
||||
.menu-horizontal > li {
|
||||
.menu-horizontal li {
|
||||
font-size: 1.65rem;
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,13 @@
|
||||
.chats-container {
|
||||
#column-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.sidebar-content {
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex; /* idk why but need */
|
||||
position: relative;
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#chats-container {
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#search-container, #chats-archived-container {
|
||||
display: none;
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 3;
|
||||
background: #fff;
|
||||
|
||||
&.active {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-header__btn-container {
|
||||
position: relative;
|
||||
width: 39.75px;
|
||||
@ -97,16 +67,5 @@
|
||||
}
|
||||
}
|
||||
|
||||
.search-group {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #DADCE0;
|
||||
padding: 1rem 0 .5rem;
|
||||
margin-bottom: .5rem;
|
||||
|
||||
&__name {
|
||||
color: $color-gray;
|
||||
padding: 0 1.85rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,20 @@
|
||||
.profile-container {
|
||||
#column-right {
|
||||
width: 0%;
|
||||
/* grid-column: 3; */
|
||||
position: relative;
|
||||
transition: .2s ease-in-out;
|
||||
|
||||
> .scrollable {
|
||||
min-width: 25vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media (min-width: $large-screen) {
|
||||
.profile-container {
|
||||
> .scrollable {
|
||||
min-width: calc(#{$large-screen} / 4 - 1px);
|
||||
min-width: 25vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media (min-width: $large-screen) {
|
||||
> .scrollable {
|
||||
min-width: calc(#{$large-screen} / 4 - 1px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +29,13 @@
|
||||
.sidebar-header {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
#search-private-container {
|
||||
.chats-container {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.profile-content {
|
||||
|
@ -1,31 +1,44 @@
|
||||
.sidebar {
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-left {
|
||||
border-right: 1px solid #DADCE0;
|
||||
}
|
||||
|
||||
.sidebar-right {
|
||||
border-left: 1px solid #DADCE0;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 7.5px 20px 7.5px 15px;
|
||||
min-height: 60px;
|
||||
|
||||
.sidebar-title {
|
||||
flex: 1;
|
||||
padding-left: 2rem;
|
||||
font-weight: 500;
|
||||
font-size: 1.4rem;
|
||||
&-left {
|
||||
border-right: 1px solid #DADCE0;
|
||||
}
|
||||
|
||||
.btn-icon + .btn-icon {
|
||||
margin-left: .5rem;
|
||||
&-right {
|
||||
border-left: 1px solid #DADCE0;
|
||||
}
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 7.5px 20px 7.5px 15px;
|
||||
min-height: 60px;
|
||||
|
||||
&__title {
|
||||
flex: 1;
|
||||
padding-left: 2rem;
|
||||
font-weight: 500;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.btn-icon + .btn-icon {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex; /* idk why but need */
|
||||
position: relative;
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1422,16 +1422,22 @@ div.scrollable::-webkit-scrollbar-thumb {
|
||||
}
|
||||
|
||||
.menu-horizontal {
|
||||
width: 100%;
|
||||
color: $darkgrey;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0;
|
||||
border-bottom: 1px solid $lightgrey;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
ul {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
> li {
|
||||
li {
|
||||
display: inline-block;
|
||||
padding: .75rem 1rem;
|
||||
cursor: pointer;
|
||||
@ -1439,24 +1445,27 @@ div.scrollable::-webkit-scrollbar-thumb {
|
||||
flex: 1;
|
||||
user-select: none;
|
||||
font-size: 1rem;
|
||||
|
||||
|
||||
&.active {
|
||||
position: relative;
|
||||
color: $blue;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background: $blue;
|
||||
left: 24px;
|
||||
right: 24px;
|
||||
bottom: -1px;
|
||||
height: 4px;
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__stripe {
|
||||
position: absolute;
|
||||
background: $blue;
|
||||
//left: 0;
|
||||
left: -2px;
|
||||
transition: .3s transform, .3s width;
|
||||
//transition: .3s transform;
|
||||
bottom: -1px;
|
||||
height: 4px;
|
||||
width: 1px; // need if using transform
|
||||
transform: scaleX(1) translateX(0px);
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-container {
|
||||
@ -1493,7 +1502,7 @@ div.scrollable::-webkit-scrollbar-thumb {
|
||||
}
|
||||
|
||||
.justify-start {
|
||||
justify-content: flex-start;
|
||||
justify-content: flex-start!important;
|
||||
}
|
||||
|
||||
.popup-send-photo {
|
||||
@ -1609,7 +1618,7 @@ div.scrollable::-webkit-scrollbar-thumb {
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.chats-container {
|
||||
#column-left {
|
||||
width: 25%;
|
||||
/* grid-column: 1; */
|
||||
}
|
||||
@ -1635,6 +1644,24 @@ div.scrollable::-webkit-scrollbar-thumb {
|
||||
}
|
||||
}
|
||||
|
||||
#search-container, #chats-archived-container, .sidebar-search {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 3;
|
||||
background: #fff;
|
||||
|
||||
&.active {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $large-screen) {
|
||||
border-top-width: 0;
|
||||
border-bottom-width: 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user