Folders almost ready
New CSS Polls
This commit is contained in:
parent
4c21835d40
commit
47ce25fce2
@ -1,6 +1,6 @@
|
||||
import Scrollable from "./scrollable_new";
|
||||
import appMessagesManager, { Dialog } from "../lib/appManagers/appMessagesManager";
|
||||
import { $rootScope, cancelEvent, findUpTag, findUpClassName } from "../lib/utils";
|
||||
import { $rootScope, cancelEvent, findUpClassName, findUpTag, findUpAttribute } from "../lib/utils";
|
||||
import appDialogsManager from "../lib/appManagers/appDialogsManager";
|
||||
import appChatsManager from "../lib/appManagers/appChatsManager";
|
||||
import appUsersManager from "../lib/appManagers/appUsersManager";
|
||||
@ -9,15 +9,16 @@ import appPhotosManager from "../lib/appManagers/appPhotosManager";
|
||||
|
||||
export class AppSelectPeers {
|
||||
public container = document.createElement('div');
|
||||
private list = document.createElement('ul');
|
||||
private chatsContainer = document.createElement('div');
|
||||
private scrollable: Scrollable;
|
||||
private selectedScrollable: Scrollable;
|
||||
public list = document.createElement('ul');
|
||||
public chatsContainer = document.createElement('div');
|
||||
public scrollable: Scrollable;
|
||||
public selectedScrollable: Scrollable;
|
||||
|
||||
private selectedContainer = document.createElement('div');
|
||||
private input = document.createElement('input');
|
||||
public selectedContainer = document.createElement('div');
|
||||
public input = document.createElement('input');
|
||||
|
||||
private selected: {[peerID: number]: HTMLDivElement} = {};
|
||||
//public selected: {[peerID: number]: HTMLElement} = {};
|
||||
public selected = new Set<any>();
|
||||
|
||||
public freezed = false;
|
||||
|
||||
@ -29,9 +30,13 @@ export class AppSelectPeers {
|
||||
private query = '';
|
||||
private cachedContacts: number[];
|
||||
|
||||
constructor(private appendTo: HTMLDivElement, private onChange?: (length: number) => void, private peerType: 'contacts' | 'dialogs' = 'dialogs', onFirstRender?: () => void) {
|
||||
constructor(private appendTo: HTMLElement, private onChange?: (length: number) => void, private peerType: 'contacts' | 'dialogs' = 'dialogs', onFirstRender?: () => void, private renderResultsFunc?: (peerIDs: number[]) => void) {
|
||||
this.container.classList.add('selector');
|
||||
|
||||
if(!this.renderResultsFunc) {
|
||||
this.renderResultsFunc = this.renderResults;
|
||||
}
|
||||
|
||||
let topContainer = document.createElement('div');
|
||||
topContainer.classList.add('selector-search-container');
|
||||
|
||||
@ -49,27 +54,23 @@ export class AppSelectPeers {
|
||||
this.scrollable = new Scrollable(this.chatsContainer);
|
||||
this.scrollable.setVirtualContainer(this.list);
|
||||
|
||||
this.list.addEventListener('click', (e) => {
|
||||
let target = e.target as HTMLElement;
|
||||
this.chatsContainer.addEventListener('click', (e) => {
|
||||
const target = findUpAttribute(e.target, 'data-peerID') as HTMLElement;
|
||||
cancelEvent(e);
|
||||
|
||||
if(!target) return;
|
||||
if(this.freezed) return;
|
||||
|
||||
if(target.tagName != 'LI') {
|
||||
target = findUpTag(target, 'LI');
|
||||
}
|
||||
|
||||
if(!target) return;
|
||||
|
||||
let peerID = +target.getAttribute('data-peerID');
|
||||
let key: any = target.getAttribute('data-peerID');
|
||||
key = +key || key;
|
||||
target.classList.toggle('active');
|
||||
if(peerID in this.selected) {
|
||||
this.remove(peerID);
|
||||
if(this.selected.has(key)) {
|
||||
this.remove(key);
|
||||
} else {
|
||||
this.add(peerID);
|
||||
this.add(key);
|
||||
}
|
||||
|
||||
let checkbox = target.querySelector('input') as HTMLInputElement;
|
||||
const checkbox = target.querySelector('input') as HTMLInputElement;
|
||||
checkbox.checked = !checkbox.checked;
|
||||
});
|
||||
|
||||
@ -80,9 +81,13 @@ export class AppSelectPeers {
|
||||
|
||||
if(!target) return;
|
||||
|
||||
let peerID = target.dataset.peerID;
|
||||
let li = this.list.querySelector('[data-peerid="' + peerID + '"]') as HTMLElement;
|
||||
li.click();
|
||||
const peerID = target.dataset.key;
|
||||
const li = this.chatsContainer.querySelector('[data-peerid="' + peerID + '"]') as HTMLElement;
|
||||
if(!li) {
|
||||
this.remove(+peerID || peerID);
|
||||
} else {
|
||||
li.click();
|
||||
}
|
||||
});
|
||||
|
||||
this.input.addEventListener('input', () => {
|
||||
@ -110,12 +115,15 @@ export class AppSelectPeers {
|
||||
this.container.append(topContainer, delimiter, this.chatsContainer);
|
||||
appendTo.append(this.container);
|
||||
|
||||
let getResultsPromise = this.getMoreResults() as Promise<any>;
|
||||
if(onFirstRender) {
|
||||
getResultsPromise.then(() => {
|
||||
onFirstRender();
|
||||
});
|
||||
}
|
||||
// WARNING TIMEOUT
|
||||
setTimeout(() => {
|
||||
let getResultsPromise = this.getMoreResults() as Promise<any>;
|
||||
if(onFirstRender) {
|
||||
getResultsPromise.then(() => {
|
||||
onFirstRender();
|
||||
});
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private async getMoreDialogs() {
|
||||
@ -144,7 +152,7 @@ export class AppSelectPeers {
|
||||
|
||||
this.offsetIndex = newOffsetIndex;
|
||||
|
||||
this.renderResults(dialogs.map(dialog => dialog.peerID));
|
||||
this.renderResultsFunc(dialogs.map(dialog => dialog.peerID));
|
||||
|
||||
this.promise = null;
|
||||
}
|
||||
@ -162,7 +170,7 @@ export class AppSelectPeers {
|
||||
if(this.cachedContacts.length) {
|
||||
const pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;
|
||||
const arr = this.cachedContacts.splice(0, pageCount);
|
||||
this.renderResults(arr);
|
||||
this.renderResultsFunc(arr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +186,10 @@ export class AppSelectPeers {
|
||||
//console.log('will renderResults:', peerIDs);
|
||||
peerIDs.forEach(peerID => {
|
||||
const {dom} = appDialogsManager.addDialog(peerID, this.scrollable, false, false);
|
||||
dom.containerEl.insertAdjacentHTML('afterbegin', '<div class="checkbox"><label><input type="checkbox"><span></span></label></div>');
|
||||
|
||||
const selected = this.selected.has(peerID);
|
||||
dom.containerEl.insertAdjacentHTML('afterbegin', `<div class="checkbox"><label><input type="checkbox" ${selected ? 'checked' : ''}><span></span></label></div>`);
|
||||
if(selected) dom.listEl.classList.add('active');
|
||||
|
||||
let subtitle = '';
|
||||
if(peerID < 0) {
|
||||
@ -196,40 +207,53 @@ export class AppSelectPeers {
|
||||
});
|
||||
}
|
||||
|
||||
private add(peerID: number) {
|
||||
public add(peerID: any, title?: string) {
|
||||
console.trace('add');
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('selector-user', 'scale-in');
|
||||
div.dataset.peerID = '' + peerID;
|
||||
this.selected[peerID] = div;
|
||||
|
||||
const title = appPeersManager.getPeerTitle(peerID, false, true);
|
||||
|
||||
const avatarEl = document.createElement('avatar-element');
|
||||
avatarEl.classList.add('selector-user-avatar', 'tgico');
|
||||
avatarEl.setAttribute('dialog', '1');
|
||||
avatarEl.setAttribute('peer', '' + peerID);
|
||||
|
||||
div.innerHTML = title;
|
||||
div.dataset.key = '' + peerID;
|
||||
this.selected.add(peerID);
|
||||
if(typeof(peerID) === 'number') {
|
||||
if(title === undefined) {
|
||||
title = peerID == $rootScope.myID ? 'Saved' : appPeersManager.getPeerTitle(peerID, false, true);
|
||||
}
|
||||
|
||||
avatarEl.setAttribute('peer', '' + peerID);
|
||||
}
|
||||
|
||||
if(title) {
|
||||
div.innerHTML = title;
|
||||
}
|
||||
|
||||
div.insertAdjacentElement('afterbegin', avatarEl);
|
||||
|
||||
this.selectedContainer.insertBefore(div, this.input);
|
||||
this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight;
|
||||
this.onChange && this.onChange(Object.keys(this.selected).length);
|
||||
//this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight;
|
||||
this.selectedScrollable.scrollTo(this.selectedScrollable.scrollHeight, true, true);
|
||||
this.onChange && this.onChange(this.selected.size);
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
private remove(peerID: number) {
|
||||
const div = this.selected[peerID];
|
||||
public remove(key: any) {
|
||||
//const div = this.selected[peerID];
|
||||
const div = this.selectedContainer.querySelector(`[data-key="${key}"]`) as HTMLElement;
|
||||
div.classList.remove('scale-in');
|
||||
void div.offsetWidth;
|
||||
div.classList.add('scale-out');
|
||||
div.addEventListener('animationend', () => {
|
||||
delete this.selected[peerID];
|
||||
this.selected.delete(key);
|
||||
div.remove();
|
||||
this.onChange && this.onChange(Object.keys(this.selected).length);
|
||||
this.onChange && this.onChange(this.selected.size);
|
||||
}, {once: true});
|
||||
}
|
||||
|
||||
public getSelected() {
|
||||
return Object.keys(this.selected).map(p => +p);
|
||||
return [...this.selected];
|
||||
}
|
||||
}
|
@ -320,8 +320,8 @@ class StickersTab implements EmoticonsTab {
|
||||
loop: true,
|
||||
autoplay: false,
|
||||
animationData: JSON.parse(json),
|
||||
width: 40,
|
||||
height: 40
|
||||
width: 32,
|
||||
height: 32
|
||||
}, EMOTICONSSTICKERGROUP);
|
||||
});
|
||||
|
||||
|
@ -5,6 +5,7 @@ let rippleClickID = 0;
|
||||
export function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null) {
|
||||
//return;
|
||||
if(elem.querySelector('.c-ripple')) return;
|
||||
elem.classList.add('rp');
|
||||
|
||||
let r = document.createElement('div');
|
||||
r.classList.add('c-ripple');
|
||||
@ -250,13 +251,28 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?
|
||||
let prevTabContent: HTMLElement = null;
|
||||
let prevId = -1;
|
||||
|
||||
const selectTab = async(id: number) => {
|
||||
const selectTab = (id: number) => {
|
||||
if(id == prevId) return false;
|
||||
|
||||
//console.log('selectTab id:', id);
|
||||
|
||||
const p = prevTabContent;
|
||||
const tabContent = content.children[id] as HTMLElement;
|
||||
|
||||
if(content.dataset.slider == 'none') {
|
||||
if(p) {
|
||||
p.classList.remove('active');
|
||||
}
|
||||
|
||||
tabContent.classList.add('active');
|
||||
|
||||
prevId = id;
|
||||
prevTabContent = tabContent;
|
||||
|
||||
if(onTransitionEnd) onTransitionEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
const toRight = prevId < id;
|
||||
if(prevId != -1) {
|
||||
if(tabs || content.dataset.slider == 'tabs') {
|
||||
|
@ -241,6 +241,10 @@ export default class PollElement extends HTMLElement {
|
||||
this.classList.add('is-quiz');
|
||||
|
||||
if(poll.close_period && poll.close_date) {
|
||||
const timeLeftDiv = document.createElement('div');
|
||||
timeLeftDiv.classList.add('poll-time');
|
||||
this.descDiv.append(timeLeftDiv);
|
||||
|
||||
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
//svg.setAttributeNS(null, 'viewBox', '0 0 15 15');
|
||||
svg.classList.add('poll-quiz-timer');
|
||||
@ -248,30 +252,52 @@ export default class PollElement extends HTMLElement {
|
||||
this.quizTimer = svg;
|
||||
|
||||
const strokeWidth = 2;
|
||||
const radius = (15 / 2) - (strokeWidth * 2);
|
||||
const radius = 7;
|
||||
const circumference = 2 * Math.PI * radius;
|
||||
|
||||
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
||||
circle.classList.add('poll-quiz-timer-circle');
|
||||
circle.setAttributeNS(null, 'cx', '15');
|
||||
circle.setAttributeNS(null, 'cy', '15');
|
||||
circle.setAttributeNS(null, 'cx', '16');
|
||||
circle.setAttributeNS(null, 'cy', '16');
|
||||
circle.setAttributeNS(null, 'r', '' + radius);
|
||||
circle.setAttributeNS(null, 'stroke-width', '' + strokeWidth);
|
||||
|
||||
svg.append(circle);
|
||||
|
||||
this.descDiv.append(svg);
|
||||
|
||||
|
||||
const period = poll.close_period * 1000;
|
||||
const closeTime = (poll.close_date - serverTimeManager.serverTimeOffset) * 1000;
|
||||
|
||||
// let time = Date.now();
|
||||
// let percents = (closeTime - time) / period;
|
||||
|
||||
// timeLeftDiv.innerHTML = String((closeTime - time) / 1000 + 1 | 0).toHHMMSS();
|
||||
|
||||
// // @ts-ignore
|
||||
// circle.style.strokeDashoffset = circumference + percents * circumference;
|
||||
// circle.style.strokeDasharray = ${circumference} ${circumference};
|
||||
|
||||
this.quizInterval = setInterval(() => {
|
||||
const time = Date.now();
|
||||
|
||||
const totalLength = circle.getTotalLength();
|
||||
const percents = (closeTime - time) / period;
|
||||
circle.style.strokeDasharray = '' + (percents * totalLength) + ', ' + circumference;
|
||||
const timeLeft = (closeTime - time) / 1000 + 1 | 0;
|
||||
timeLeftDiv.innerHTML = String(timeLeft).toHHMMSS();
|
||||
|
||||
if (timeLeft <= 5) {
|
||||
timeLeftDiv.style.color = '#ee545c';
|
||||
circle.style.stroke = '#ee545c';
|
||||
}
|
||||
//timeLeftDiv.style.visibility = 'visible';
|
||||
|
||||
// @ts-ignore
|
||||
circle.style.strokeDashoffset = circumference + percents * circumference;
|
||||
circle.style.strokeDasharray = `${circumference} ${circumference}`;
|
||||
|
||||
if(time >= closeTime) {
|
||||
clearInterval(this.quizInterval);
|
||||
timeLeftDiv.innerHTML = '';
|
||||
// @ts-ignore
|
||||
circle.style.strokeDashoffset = circumference;
|
||||
this.quizInterval = 0;
|
||||
|
||||
// нужно запросить апдейт чтобы опрос обновился
|
||||
@ -487,7 +513,7 @@ export default class PollElement extends HTMLElement {
|
||||
* все приложения накладывают аватарку первую на вторую, а в макете зато вторая на первую, ЛОЛ!
|
||||
*/
|
||||
results.recent_voters/* .slice().reverse() */.forEach((userID, idx) => {
|
||||
const style = idx == 0 ? '' : `style="transform: translateX(-${idx * 5}px);"`;
|
||||
const style = idx == 0 ? '' : `style="transform: translateX(-${idx * 3}px);"`;
|
||||
html += `<avatar-element dialog="0" peer="${userID}" ${style}></avatar-element>`;
|
||||
});
|
||||
this.avatarsDiv.innerHTML = html;
|
||||
|
@ -29,17 +29,20 @@ export default class PopupCreatePoll extends PopupElement {
|
||||
|
||||
this.title.innerText = 'New Poll';
|
||||
|
||||
const questionField = InputField('Ask a question', 'Ask a question', 'question');
|
||||
const questionField = InputField('Ask a Question', 'Ask a Question', 'question');
|
||||
this.questionInput = questionField.firstElementChild as HTMLInputElement;
|
||||
|
||||
this.header.append(questionField);
|
||||
|
||||
const hr = document.createElement('hr');
|
||||
const d = document.createElement('div');
|
||||
d.classList.add('caption');
|
||||
d.innerText = 'Options';
|
||||
|
||||
this.questions = document.createElement('div');
|
||||
this.questions.classList.add('poll-create-questions');
|
||||
|
||||
this.body.parentElement.insertBefore(hr, this.body);
|
||||
this.body.append(d, this.questions);
|
||||
|
||||
this.confirmBtn.addEventListener('click', this.onSubmitClick);
|
||||
|
@ -82,6 +82,8 @@ export default class Scrollable {
|
||||
public scrollLocked = 0;
|
||||
public isVisible = false;
|
||||
|
||||
private reorderTimeout: number;
|
||||
|
||||
private setVisible(element: HTMLElement) {
|
||||
if(this.visible.has(element)) return;
|
||||
|
||||
@ -373,9 +375,15 @@ export default class Scrollable {
|
||||
}
|
||||
|
||||
public reorder() {
|
||||
(Array.from(this.splitUp.children) as HTMLElement[]).forEach((el, idx) => {
|
||||
el.dataset.virtual = '' + idx;
|
||||
});
|
||||
if(!this.splitUp || this.reorderTimeout) return;
|
||||
|
||||
this.reorderTimeout = setTimeout(() => {
|
||||
this.reorderTimeout = 0;
|
||||
|
||||
(Array.from(this.splitUp.children) as HTMLElement[]).forEach((el, idx) => {
|
||||
el.dataset.virtual = '' + idx;
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public updateElement(element: HTMLElement) {
|
||||
|
187
src/components/sidebarLeft/chatFolders.ts
Normal file
187
src/components/sidebarLeft/chatFolders.ts
Normal file
@ -0,0 +1,187 @@
|
||||
import { SliderTab } from "../slider";
|
||||
import lottieLoader, { RLottiePlayer } from "../../lib/lottieLoader";
|
||||
import apiManager from "../../lib/mtproto/mtprotoworker";
|
||||
import appMessagesManager, { DialogFilter } from "../../lib/appManagers/appMessagesManager";
|
||||
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||
import appPeersManager from "../../lib/appManagers/appPeersManager";
|
||||
import { ripple } from "../misc";
|
||||
import { $rootScope, cancelEvent } from "../../lib/utils";
|
||||
import appSidebarLeft from "../../lib/appManagers/appSidebarLeft";
|
||||
|
||||
type DialogFilterSuggested = {
|
||||
_: 'dialogFilterSuggested',
|
||||
filter: DialogFilter,
|
||||
description: string
|
||||
};
|
||||
|
||||
export default class AppChatFoldersTab implements SliderTab {
|
||||
public container: HTMLElement;
|
||||
public createFolderBtn: HTMLElement;
|
||||
private foldersContainer: HTMLElement;
|
||||
private suggestedContainer: HTMLElement;
|
||||
private stickerContainer: HTMLElement;
|
||||
private animation: RLottiePlayer;
|
||||
|
||||
private filtersRendered: {[filterID: number]: HTMLElement} = {};
|
||||
|
||||
private renderFolder(dialogFilter: DialogFilterSuggested | DialogFilter, container?: HTMLElement, div: HTMLElement = document.createElement('div')) {
|
||||
let filter: DialogFilter;
|
||||
let description = '';
|
||||
let d: string[] = [];
|
||||
if(dialogFilter._ == 'dialogFilterSuggested') {
|
||||
filter = dialogFilter.filter;
|
||||
description = dialogFilter.description;
|
||||
} else {
|
||||
filter = dialogFilter;
|
||||
description = '';
|
||||
|
||||
const filterID = filter.id;
|
||||
if(!this.filtersRendered.hasOwnProperty(filter.id)) {
|
||||
div.addEventListener('click', () => {
|
||||
appSidebarLeft.editFolderTab.open(appMessagesManager.filtersStorage.filters[filterID]);
|
||||
});
|
||||
}
|
||||
|
||||
this.filtersRendered[filter.id] = div;
|
||||
|
||||
let enabledFilters = Object.keys(filter.pFlags).length;
|
||||
/* (['include_peers', 'exclude_peers'] as ['include_peers', 'exclude_peers']).forEach(key => {
|
||||
enabledFilters += +!!filter[key].length;
|
||||
}); */
|
||||
|
||||
if(enabledFilters == 1) {
|
||||
description = 'All ';
|
||||
|
||||
const pFlags = filter.pFlags;
|
||||
if(pFlags.contacts) description += 'Contacts';
|
||||
else if(pFlags.non_contacts) description += 'Non-Contacts';
|
||||
else if(pFlags.groups) description += 'Groups';
|
||||
else if(pFlags.broadcasts) description += 'Channels';
|
||||
else if(pFlags.bots) description += 'Bots';
|
||||
else if(pFlags.exclude_muted) description += 'Unmuted';
|
||||
else if(pFlags.exclude_read) description += 'Unread';
|
||||
else if(pFlags.exclude_archived) description += 'Unarchived';
|
||||
d.push(description);
|
||||
} else {
|
||||
const folder = appMessagesManager.dialogsStorage.getFolder(filter.id);
|
||||
let chats = 0, channels = 0, groups = 0;
|
||||
for(const dialog of folder) {
|
||||
if(appPeersManager.isAnyGroup(dialog.peerID)) groups++;
|
||||
else if(appPeersManager.isBroadcast(dialog.peerID)) channels++;
|
||||
else chats++;
|
||||
}
|
||||
|
||||
if(chats) d.push(chats + ' chats');
|
||||
if(channels) d.push(channels + ' channels');
|
||||
if(groups) d.push(groups + ' groups');
|
||||
}
|
||||
}
|
||||
|
||||
div.classList.add('category');
|
||||
div.innerHTML = `
|
||||
<div>
|
||||
<p>${RichTextProcessor.wrapEmojiText(filter.title)}</p>
|
||||
<p>${d.length ? d.join(', ') : description}</p>
|
||||
</div>
|
||||
`;
|
||||
ripple(div);
|
||||
|
||||
if(container) container.append(div);
|
||||
return div;
|
||||
}
|
||||
|
||||
init() {
|
||||
this.container = document.querySelector('.chat-folders-container');
|
||||
this.stickerContainer = this.container.querySelector('.sticker-container');
|
||||
this.foldersContainer = this.container.querySelector('.folders-my');
|
||||
this.suggestedContainer = this.container.querySelector('.folders-suggested');
|
||||
this.createFolderBtn = this.container.querySelector('.btn-create-folder');
|
||||
|
||||
this.createFolderBtn.addEventListener('click', () => {
|
||||
appSidebarLeft.editFolderTab.open();
|
||||
});
|
||||
|
||||
lottieLoader.loadAnimationFromURL({
|
||||
container: this.stickerContainer,
|
||||
loop: false,
|
||||
autoplay: true,
|
||||
width: 86,
|
||||
height: 86
|
||||
}, 'assets/img/Folders_1.tgs').then(player => {
|
||||
this.animation = player;
|
||||
});
|
||||
|
||||
appMessagesManager.filtersStorage.getDialogFilters().then(filters => {
|
||||
for(const filterID in filters) {
|
||||
const filter = filters[filterID];
|
||||
this.renderFolder(filter, this.foldersContainer);
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('filter_update', (e: CustomEvent) => {
|
||||
const filter: DialogFilter = e.detail;
|
||||
if(this.filtersRendered.hasOwnProperty(filter.id)) {
|
||||
this.renderFolder(filter, null, this.filtersRendered[filter.id]);
|
||||
} else {
|
||||
this.renderFolder(filter, this.foldersContainer);
|
||||
}
|
||||
|
||||
this.getSuggestedFilters();
|
||||
});
|
||||
|
||||
$rootScope.$on('filter_delete', (e: CustomEvent) => {
|
||||
const filter: DialogFilter = e.detail;
|
||||
if(this.filtersRendered.hasOwnProperty(filter.id)) {
|
||||
/* for(const suggested of this.suggestedFilters) {
|
||||
if(deepEqual(suggested.filter, filter)) {
|
||||
|
||||
}
|
||||
} */
|
||||
this.getSuggestedFilters();
|
||||
|
||||
this.filtersRendered[filter.id].remove();
|
||||
delete this.filtersRendered[filter.id]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getSuggestedFilters() {
|
||||
apiManager.invokeApi('messages.getSuggestedDialogFilters').then(suggestedFilters => {
|
||||
this.suggestedContainer.style.display = suggestedFilters.length ? '' : 'none';
|
||||
Array.from(this.suggestedContainer.children).slice(1).forEach(el => el.remove());
|
||||
|
||||
(suggestedFilters as DialogFilterSuggested[]).forEach(filter => {
|
||||
const div = this.renderFolder(filter);
|
||||
const button = document.createElement('button');
|
||||
button.classList.add('btn-primary');
|
||||
button.innerText = 'Add';
|
||||
div.append(button);
|
||||
this.suggestedContainer.append(div);
|
||||
|
||||
button.addEventListener('click', (e) => {
|
||||
cancelEvent(e);
|
||||
button.setAttribute('disabled', 'true');
|
||||
|
||||
appMessagesManager.filtersStorage.createDialogFilter(filter.filter).then(bool => {
|
||||
if(bool) {
|
||||
div.remove();
|
||||
}
|
||||
}).finally(() => {
|
||||
button.removeAttribute('disabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
if(this.init) {
|
||||
this.init();
|
||||
this.init = null;
|
||||
} else {
|
||||
if(this.animation) {
|
||||
this.animation.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ export default class AppContactsTab implements SliderTab {
|
||||
this.container.firstElementChild.append(this.searchInput.container);
|
||||
|
||||
// preload contacts
|
||||
appUsersManager.getContacts();
|
||||
// appUsersManager.getContacts();
|
||||
}
|
||||
|
||||
// need to clear, and left 1 page for smooth slide
|
||||
@ -49,7 +49,7 @@ export default class AppContactsTab implements SliderTab {
|
||||
if(this.promise) return this.promise;
|
||||
this.scrollable.onScrolledBottom = null;
|
||||
|
||||
this.promise = appUsersManager.getContacts(query).then(contacts => {
|
||||
this.promise = appUsersManager.getContacts(query).then(_contacts => {
|
||||
this.promise = null;
|
||||
|
||||
if(appSidebarLeft.historyTabIDs[appSidebarLeft.historyTabIDs.length - 1] != AppSidebarLeft.SLIDERITEMSIDS.contacts) {
|
||||
@ -57,7 +57,7 @@ export default class AppContactsTab implements SliderTab {
|
||||
return;
|
||||
}
|
||||
|
||||
contacts = contacts.slice();
|
||||
const contacts = [..._contacts];
|
||||
contacts.findAndSplice(u => u == $rootScope.myID);
|
||||
|
||||
let sorted = contacts
|
||||
|
249
src/components/sidebarLeft/editFolder.ts
Normal file
249
src/components/sidebarLeft/editFolder.ts
Normal file
@ -0,0 +1,249 @@
|
||||
import { SliderTab } from "../slider";
|
||||
import appSidebarLeft, { AppSidebarLeft } from "../../lib/appManagers/appSidebarLeft";
|
||||
import lottieLoader, { RLottiePlayer } from "../../lib/lottieLoader";
|
||||
import appMessagesManager, { DialogFilter, Dialog } from "../../lib/appManagers/appMessagesManager";
|
||||
import { parseMenuButtonsTo, ripple, toast } from "../misc";
|
||||
import appDialogsManager from "../../lib/appManagers/appDialogsManager";
|
||||
import { copy, deepEqual } from "../../lib/utils";
|
||||
|
||||
export default class AppEditFolderTab implements SliderTab {
|
||||
public container: HTMLElement;
|
||||
private closeBtn: HTMLElement;
|
||||
private title: HTMLElement;
|
||||
private caption: HTMLElement;
|
||||
private stickerContainer: HTMLElement;
|
||||
|
||||
private confirmBtn: HTMLElement;
|
||||
private menuBtn: HTMLElement;
|
||||
private deleteFolderBtn: HTMLElement;
|
||||
private nameInput: HTMLInputElement;
|
||||
|
||||
private include_peers: HTMLElement;
|
||||
private exclude_peers: HTMLElement;
|
||||
private flags: {[k in 'contacts' | 'non_contacts' | 'groups' | 'broadcasts' | 'bots' | 'exclude_muted' | 'exclude_archived' | 'exclude_read']: HTMLElement} = {} as any;
|
||||
|
||||
private animation: RLottiePlayer;
|
||||
private filter: DialogFilter;
|
||||
private originalFilter: DialogFilter;
|
||||
|
||||
private type: 'edit' | 'create';
|
||||
|
||||
init() {
|
||||
this.container = document.querySelector('.edit-folder-container');
|
||||
this.closeBtn = this.container.querySelector('.sidebar-close-button');
|
||||
this.title = this.container.querySelector('.sidebar-header__title');
|
||||
this.caption = this.container.querySelector('.caption');
|
||||
this.stickerContainer = this.container.querySelector('.sticker-container');
|
||||
|
||||
this.confirmBtn = this.container.querySelector('.btn-confirm');
|
||||
this.menuBtn = this.container.querySelector('.btn-menu-toggle');
|
||||
this.deleteFolderBtn = this.menuBtn.querySelector('.menu-delete');
|
||||
this.nameInput = this.container.querySelector('#folder-name');
|
||||
|
||||
this.include_peers = this.container.querySelector('.folder-list-included');
|
||||
this.exclude_peers = this.container.querySelector('.folder-list-excluded');
|
||||
|
||||
const includedFlagsContainer = this.include_peers.querySelector('.folder-categories');
|
||||
const excludedFlagsContainer = this.exclude_peers.querySelector('.folder-categories');
|
||||
parseMenuButtonsTo(this.flags, includedFlagsContainer.children);
|
||||
parseMenuButtonsTo(this.flags, excludedFlagsContainer.children);
|
||||
|
||||
includedFlagsContainer.firstElementChild.addEventListener('click', () => {
|
||||
appSidebarLeft.includedChatsTab.open(this.filter, 'included');
|
||||
});
|
||||
|
||||
excludedFlagsContainer.firstElementChild.addEventListener('click', () => {
|
||||
appSidebarLeft.includedChatsTab.open(this.filter, 'excluded');
|
||||
});
|
||||
|
||||
lottieLoader.loadAnimationFromURL({
|
||||
container: this.stickerContainer,
|
||||
loop: true,
|
||||
autoplay: true,
|
||||
width: 86,
|
||||
height: 86
|
||||
}, 'assets/img/Folders_2.tgs').then(player => {
|
||||
this.animation = player;
|
||||
});
|
||||
|
||||
this.deleteFolderBtn.addEventListener('click', () => {
|
||||
this.deleteFolderBtn.setAttribute('disabled', 'true');
|
||||
appMessagesManager.filtersStorage.updateDialogFilter(this.filter, true).then(bool => {
|
||||
if(bool) {
|
||||
this.closeBtn.click();
|
||||
}
|
||||
}).finally(() => {
|
||||
this.deleteFolderBtn.removeAttribute('disabled');
|
||||
});
|
||||
});
|
||||
|
||||
this.confirmBtn.addEventListener('click', () => {
|
||||
if(!this.nameInput.value.trim()) {
|
||||
this.nameInput.classList.add('error');
|
||||
return;
|
||||
}
|
||||
|
||||
let include = (Array.from(includedFlagsContainer.children) as HTMLElement[]).slice(1).reduce((acc, el) => acc + +!el.style.display, 0);
|
||||
if(this.include_peers.lastElementChild.tagName == 'UL') {
|
||||
include += this.include_peers.lastElementChild.childElementCount;
|
||||
}
|
||||
|
||||
if(!include) {
|
||||
toast('Please choose at least one chat for this folder.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.confirmBtn.setAttribute('disabled', 'true');
|
||||
|
||||
let promise: Promise<boolean>;
|
||||
if(!this.filter.id) {
|
||||
promise = appMessagesManager.filtersStorage.createDialogFilter(this.filter);
|
||||
} else {
|
||||
promise = appMessagesManager.filtersStorage.updateDialogFilter(this.filter);
|
||||
}
|
||||
|
||||
promise.then(bool => {
|
||||
if(bool) {
|
||||
this.closeBtn.click();
|
||||
}
|
||||
}).finally(() => {
|
||||
this.confirmBtn.removeAttribute('disabled');
|
||||
});
|
||||
});
|
||||
|
||||
this.nameInput.addEventListener('input', () => {
|
||||
this.filter.title = this.nameInput.value;
|
||||
this.nameInput.classList.remove('error');
|
||||
|
||||
this.editCheckForChange();
|
||||
});
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
if(this.init) {
|
||||
this.init();
|
||||
this.init = null;
|
||||
} else {
|
||||
if(this.animation) {
|
||||
this.animation.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
Array.from(this.container.querySelectorAll('ul, .show-more')).forEach(el => el.remove());
|
||||
}
|
||||
|
||||
private onCreateOpen() {
|
||||
this.caption.style.display = '';
|
||||
this.title.innerText = 'New Folder';
|
||||
this.menuBtn.classList.add('hide');
|
||||
this.confirmBtn.classList.remove('hide');
|
||||
this.nameInput.value = '';
|
||||
|
||||
for(const flag in this.flags) {
|
||||
// @ts-ignore
|
||||
this.flags[flag].style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
private onEditOpen() {
|
||||
this.caption.style.display = 'none';
|
||||
this.title.innerText = this.type == 'create' ? 'New Folder' : 'Edit Folder';
|
||||
|
||||
if(this.type == 'edit') {
|
||||
this.menuBtn.classList.remove('hide');
|
||||
this.confirmBtn.classList.add('hide');
|
||||
}
|
||||
|
||||
const filter = this.filter;
|
||||
this.nameInput.value = filter.title;
|
||||
|
||||
for(const flag in this.flags) {
|
||||
// @ts-ignore
|
||||
this.flags[flag].style.display = !!filter.pFlags[flag] ? '' : 'none';
|
||||
}
|
||||
|
||||
(['include_peers', 'exclude_peers'] as ['include_peers', 'exclude_peers']).forEach(key => {
|
||||
const container = this[key];
|
||||
const ul = document.createElement('ul');
|
||||
|
||||
const peers = filter[key].slice();
|
||||
|
||||
const renderMore = (_length: number) => {
|
||||
for(let i = 0, length = Math.min(peers.length, _length); i < length; ++i) {
|
||||
const peerID = peers.shift();
|
||||
|
||||
const {dom} = appDialogsManager.addDialog(peerID, ul, false, false, undefined, true);
|
||||
dom.lastMessageSpan.parentElement.remove();
|
||||
}
|
||||
|
||||
if(peers.length) {
|
||||
showMore.innerHTML = `<div class="tgico-down"></div><div>Show ${Math.min(20, peers.length)} more chat${peers.length > 1 ? 's' : ''}</div>`;
|
||||
} else if(showMore) {
|
||||
showMore.remove();
|
||||
}
|
||||
};
|
||||
|
||||
container.append(ul);
|
||||
|
||||
let showMore: HTMLElement;
|
||||
if(peers.length) {
|
||||
showMore = document.createElement('div');
|
||||
showMore.classList.add('show-more');
|
||||
showMore.addEventListener('click', () => renderMore(20));
|
||||
|
||||
showMore.innerHTML = `<div class="tgico-down"></div><div>Show ${Math.min(20, peers.length)} more chat${peers.length > 1 ? 's' : ''}</div>`;
|
||||
ripple(showMore);
|
||||
container.append(showMore);
|
||||
}
|
||||
|
||||
renderMore(4);
|
||||
});
|
||||
}
|
||||
|
||||
editCheckForChange() {
|
||||
if(this.type == 'edit') {
|
||||
const changed = !deepEqual(this.originalFilter, this.filter);
|
||||
this.confirmBtn.classList.toggle('hide', !changed);
|
||||
this.menuBtn.classList.toggle('hide', changed);
|
||||
}
|
||||
};
|
||||
|
||||
setFilter(filter: DialogFilter, firstTime: boolean) {
|
||||
// cleanup
|
||||
this.onCloseAfterTimeout();
|
||||
|
||||
if(firstTime) {
|
||||
this.originalFilter = filter;
|
||||
this.filter = copy(filter);
|
||||
} else {
|
||||
this.filter = filter;
|
||||
this.onEditOpen();
|
||||
this.editCheckForChange();
|
||||
}
|
||||
}
|
||||
|
||||
open(filter?: DialogFilter) {
|
||||
appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.editFolder);
|
||||
|
||||
if(filter === undefined) {
|
||||
this.setFilter({
|
||||
_: 'dialogFilter',
|
||||
flags: 0,
|
||||
id: 0,
|
||||
title: '',
|
||||
pFlags: {},
|
||||
pinned_peers: [],
|
||||
include_peers: [],
|
||||
exclude_peers: []
|
||||
}, true);
|
||||
this.type = 'create';
|
||||
this.onCreateOpen();
|
||||
} else {
|
||||
this.setFilter(filter, true);
|
||||
this.type = 'edit';
|
||||
this.onEditOpen();
|
||||
}
|
||||
}
|
||||
}
|
186
src/components/sidebarLeft/includedChats.ts
Normal file
186
src/components/sidebarLeft/includedChats.ts
Normal file
@ -0,0 +1,186 @@
|
||||
import { SliderTab } from "../slider";
|
||||
import { AppSelectPeers } from "../appSelectPeers";
|
||||
import appSidebarLeft, { AppSidebarLeft } from "../../lib/appManagers/appSidebarLeft";
|
||||
import appDialogsManager from "../../lib/appManagers/appDialogsManager";
|
||||
import appPeersManager from "../../lib/appManagers/appPeersManager";
|
||||
import appUsersManager from "../../lib/appManagers/appUsersManager";
|
||||
import { $rootScope, copy, deepEqual } from "../../lib/utils";
|
||||
import { DialogFilter } from "../../lib/appManagers/appMessagesManager";
|
||||
|
||||
export default class AppIncludedChatsTab implements SliderTab {
|
||||
public container: HTMLElement;
|
||||
private closeBtn: HTMLElement;
|
||||
private confirmBtn: HTMLElement;
|
||||
private title: HTMLElement;
|
||||
|
||||
private selector: AppSelectPeers;
|
||||
private type: 'included' | 'excluded';
|
||||
private filter: DialogFilter;
|
||||
private originalFilter: DialogFilter;
|
||||
|
||||
init() {
|
||||
this.container = document.querySelector('.included-chats-container');
|
||||
this.closeBtn = this.container.querySelector('.sidebar-close-button');
|
||||
this.confirmBtn = this.container.querySelector('.btn-confirm');
|
||||
this.title = this.container.querySelector('.sidebar-header__title');
|
||||
|
||||
this.confirmBtn.addEventListener('click', () => {
|
||||
const selected = this.selector.getSelected();
|
||||
|
||||
this.filter.pFlags = {};
|
||||
|
||||
const peers: number[] = [];
|
||||
for(const key of selected) {
|
||||
if(typeof(key) === 'number') {
|
||||
peers.push(key);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
this.filter.pFlags[key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.filter[this.type == 'included' ? 'include_peers' : 'exclude_peers'] = peers;
|
||||
|
||||
appSidebarLeft.editFolderTab.setFilter(this.filter, false);
|
||||
this.closeBtn.click();
|
||||
});
|
||||
}
|
||||
|
||||
checkbox(selected?: boolean) {
|
||||
return `<div class="checkbox"><label><input type="checkbox" ${selected ? 'checked' : ''}><span></span></label></div>`;
|
||||
}
|
||||
|
||||
renderResults = (peerIDs: number[]) => {
|
||||
const other = this.type == 'included' ? this.filter.exclude_peers : this.filter.include_peers;
|
||||
|
||||
peerIDs.forEach(peerID => {
|
||||
if(other.includes(peerID)) return;
|
||||
|
||||
const {dom} = appDialogsManager.addDialog(peerID, this.selector.scrollable, false, false);
|
||||
|
||||
const selected = this.selector.selected.has(peerID);
|
||||
dom.containerEl.insertAdjacentHTML('beforeend', this.checkbox(selected));
|
||||
if(selected) dom.listEl.classList.add('active');
|
||||
|
||||
let subtitle = '';
|
||||
|
||||
if(peerID > 0) {
|
||||
if(peerID == $rootScope.myID) {
|
||||
subtitle = 'Chat with yourself';
|
||||
} else if(appUsersManager.isBot(peerID)) {
|
||||
subtitle = 'Bot';
|
||||
} else {
|
||||
subtitle = appUsersManager.contactsList.has(peerID) ? 'Contact' : 'Non-Contact';
|
||||
}
|
||||
} else {
|
||||
subtitle = appPeersManager.isBroadcast(peerID) ? 'Channel' : 'Group';
|
||||
}
|
||||
|
||||
dom.lastMessageSpan.innerHTML = subtitle;
|
||||
});
|
||||
};
|
||||
|
||||
onOpen() {
|
||||
if(this.init) {
|
||||
this.init();
|
||||
this.init = null;
|
||||
}
|
||||
|
||||
this.confirmBtn.style.display = this.type == 'excluded' ? '' : 'none';
|
||||
this.title.innerText = this.type == 'included' ? 'Included Chats' : 'Excluded Chats';
|
||||
|
||||
const filter = this.filter;
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
const dd = document.createElement('div');
|
||||
dd.classList.add('sidebar-left-h2');
|
||||
dd.innerText = 'Chat types';
|
||||
|
||||
const categories = document.createElement('div');
|
||||
categories.classList.add('folder-categories');
|
||||
|
||||
let details: any;
|
||||
if(this.type == 'excluded') {
|
||||
details = {
|
||||
exclude_muted: {ico: 'tgico-mute', text: 'Muted'},
|
||||
exclude_archived: {ico: 'tgico-archive', text: 'Archived'},
|
||||
exclude_read: {ico: 'tgico-readchats', text: 'Read'}
|
||||
};
|
||||
} else {
|
||||
details = {
|
||||
contacts: {ico: 'tgico-newprivate', text: 'Contacts'},
|
||||
non_contacts: {ico: 'tgico-noncontacts', text: 'Non-Contacts'},
|
||||
groups: {ico: 'tgico-group', text: 'Groups'},
|
||||
broadcasts: {ico: 'tgico-newchannel', text: 'Channels'},
|
||||
bots: {ico: 'tgico-bots', text: 'Bots'}
|
||||
};
|
||||
}
|
||||
|
||||
let html = '';
|
||||
for(const key in details) {
|
||||
html += `<div class="folder-category-button ${details[key].ico}" data-peerID="${key}"><p>${details[key].text}</p>${this.checkbox()}</div>`;
|
||||
}
|
||||
categories.innerHTML = html;
|
||||
|
||||
const hr = document.createElement('hr');
|
||||
hr.style.margin = '7px 0 9px';
|
||||
|
||||
const d = document.createElement('div');
|
||||
d.classList.add('sidebar-left-h2');
|
||||
d.innerText = 'Chats';
|
||||
|
||||
fragment.append(dd, categories, hr, d);
|
||||
|
||||
/////////////////
|
||||
|
||||
const selectedPeers = (this.type == 'included' ? filter.include_peers : filter.exclude_peers).slice();
|
||||
|
||||
this.selector = new AppSelectPeers(this.container, this.onSelectChange, 'dialogs', null, this.renderResults);
|
||||
this.selector.selected = new Set(selectedPeers);
|
||||
this.selector.input.placeholder = 'Search';
|
||||
|
||||
const _add = this.selector.add.bind(this.selector);
|
||||
this.selector.add = (peerID, title) => {
|
||||
const div = _add(peerID, details[peerID]?.text);
|
||||
if(details[peerID]) {
|
||||
div.querySelector('avatar-element').classList.add(details[peerID].ico);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
||||
this.selector.list.parentElement.insertBefore(fragment, this.selector.list);
|
||||
|
||||
selectedPeers.forEach(peerID => {
|
||||
this.selector.add(peerID);
|
||||
});
|
||||
|
||||
for(const flag in filter.pFlags) {
|
||||
// @ts-ignore
|
||||
if(details.hasOwnProperty(flag) && !!filter.pFlags[flag]) {
|
||||
(categories.querySelector(`[data-peerID="${flag}"]`) as HTMLElement).click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onSelectChange = (length: number) => {
|
||||
//const changed = !deepEqual(this.filter, this.originalFilter);
|
||||
if(this.type == 'included') {
|
||||
this.confirmBtn.style.display = length ? '' : 'none';
|
||||
}
|
||||
};
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
if(this.selector) {
|
||||
this.selector.container.remove();
|
||||
this.selector = null;
|
||||
}
|
||||
}
|
||||
|
||||
open(filter: DialogFilter, type: 'included' | 'excluded') {
|
||||
this.originalFilter = filter;
|
||||
this.filter = copy(this.originalFilter);
|
||||
this.type = type;
|
||||
|
||||
appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.includedChats);
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ export default class AppSettingsTab implements SliderTab {
|
||||
|
||||
private buttons: {
|
||||
edit: HTMLButtonElement,
|
||||
folders: HTMLButtonElement,
|
||||
general: HTMLButtonElement,
|
||||
notifications: HTMLButtonElement,
|
||||
privacy: HTMLButtonElement,
|
||||
@ -34,8 +35,12 @@ export default class AppSettingsTab implements SliderTab {
|
||||
});
|
||||
|
||||
this.buttons.edit.addEventListener('click', () => {
|
||||
appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.editProfile);
|
||||
appSidebarLeft.editProfileTab.fillElements();
|
||||
appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.editProfile);
|
||||
});
|
||||
|
||||
this.buttons.folders.addEventListener('click', () => {
|
||||
appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.chatFolders);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,20 @@
|
||||
import { horizontalMenu } from "./misc";
|
||||
|
||||
export interface SliderTab {
|
||||
onOpen?: () => void,
|
||||
onOpenAfterTimeout?: () => void,
|
||||
onClose?: () => void,
|
||||
onCloseAfterTimeout?: () => void
|
||||
}
|
||||
|
||||
const TRANSITIONTIME = 420;
|
||||
|
||||
export default class SidebarSlider {
|
||||
protected _selectTab: (id: number) => void;
|
||||
public historyTabIDs: number[] = [];
|
||||
|
||||
constructor(public sidebarEl: HTMLElement, public tabs: {[id: number]: SliderTab}) {
|
||||
this._selectTab = horizontalMenu(null, this.sidebarEl.querySelector('.sidebar-slider') as HTMLDivElement, null, null, 420);
|
||||
this._selectTab = horizontalMenu(null, this.sidebarEl.querySelector('.sidebar-slider') as HTMLDivElement, null, null, TRANSITIONTIME);
|
||||
this._selectTab(0);
|
||||
|
||||
let onCloseBtnClick = () => {
|
||||
@ -28,6 +32,20 @@ export default class SidebarSlider {
|
||||
if(this.historyTabIDs[this.historyTabIDs.length - 1] == id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tab = this.tabs[id];
|
||||
if(tab) {
|
||||
if(tab.onOpen) {
|
||||
tab.onOpen();
|
||||
}
|
||||
|
||||
if(tab.onOpenAfterTimeout) {
|
||||
setTimeout(() => {
|
||||
tab.onOpenAfterTimeout();
|
||||
}, TRANSITIONTIME);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.historyTabIDs.push(id);
|
||||
this._selectTab(id);
|
||||
@ -41,14 +59,14 @@ export default class SidebarSlider {
|
||||
public onCloseTab(id: number) {
|
||||
let tab = this.tabs[id];
|
||||
if(tab) {
|
||||
if('onClose' in tab) {
|
||||
if(tab.onClose) {
|
||||
tab.onClose();
|
||||
}
|
||||
|
||||
if('onCloseAfterTimeout' in tab) {
|
||||
if(tab.onCloseAfterTimeout) {
|
||||
setTimeout(() => {
|
||||
tab.onCloseAfterTimeout();
|
||||
}, 420);
|
||||
}, TRANSITIONTIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +210,21 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-content">
|
||||
<div id="chats-container"><ul id="dialogs"></ul></div>
|
||||
<div id="chats-container">
|
||||
<div class="folders-tabs-scrollable">
|
||||
<nav class="menu-horizontal" style="display: none;" id="folders-tabs">
|
||||
<ul>
|
||||
<li class="rp"><span>All</span></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
{{!-- <div class="tabs-container" id="folders-container" data-slider="none"> --}}
|
||||
<div class="tabs-container" id="folders-container">
|
||||
<div>
|
||||
<ul id="dialogs"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-search hide" id="search-container"></div>
|
||||
<button class="btn-primary btn-circle btn-icon rp btn-corner tgico-newchat_filled btn-menu-toggle" id="new-menu">
|
||||
<div class="btn-menu top-left">
|
||||
@ -311,6 +325,7 @@
|
||||
<div class="profile-subtitle"></div>
|
||||
<div class="profile-buttons">
|
||||
<div class="profile-button menu-edit tgico-edit rp"><p>Edit Profile</p></div>
|
||||
<div class="profile-button menu-folders tgico-folder rp"><p>Chat Folders</p></div>
|
||||
<div class="profile-button menu-general tgico-settings rp"><p>General Settings</p></div>
|
||||
<div class="profile-button menu-notifications tgico-unmute rp"><p>Notifications</p></div>
|
||||
<div class="profile-button menu-privacy tgico-lock rp"><p>Privacy and Security</p></div>
|
||||
@ -360,6 +375,81 @@
|
||||
<button class="btn-primary btn-circle btn-icon rp btn-corner tgico-check"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-slider-item chat-folders-container">
|
||||
<div class="sidebar-header">
|
||||
<button class="btn-icon rp tgico-back sidebar-close-button"></button>
|
||||
<div class="sidebar-header__title">Chat Folders</div>
|
||||
</div>
|
||||
<div class="sidebar-content">
|
||||
<div class="chat-folders scrollable scrollable-y">
|
||||
<div class="sticker-container"></div>
|
||||
<div class="caption">Create folders for different groups of chats<br>and quickly switch between them.</div>
|
||||
<button class="btn-primary btn-create-folder rp">
|
||||
<div class="tgico-add"></div>
|
||||
Create Folder
|
||||
</button>
|
||||
<hr/>
|
||||
<div class="folders-container folders-my">
|
||||
<div class="sidebar-left-h2">Folders</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="folders-container folders-suggested" style="display: none;">
|
||||
<div class="sidebar-left-h2">Recommended folders</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-slider-item edit-folder-container">
|
||||
<div class="sidebar-header">
|
||||
<button class="btn-icon rp tgico-back sidebar-close-button"></button>
|
||||
<div class="sidebar-header__title"></div>
|
||||
<div class="btn-icon tgico-check1 btn-confirm rp hide"></div>
|
||||
<div class="btn-icon btn-menu-toggle rp tgico-more hide">
|
||||
<div class="btn-menu bottom-left">
|
||||
<div class="btn-menu-item menu-delete tgico-delete danger rp">Delete Folder</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-content">
|
||||
<div class="edit-folder scrollable scrollable-y">
|
||||
<div class="sticker-container"></div>
|
||||
<div class="caption">Choose chats and types of chats that will<br>appear and never appear in this folder.</div>
|
||||
<div class="input-wrapper">
|
||||
<div class="input-field">
|
||||
<input type="text" name="folder-name" class="folder-name" autocomplete="aintCCZsofunnowhHQ" id="folder-name" required="">
|
||||
<label for="folder-name">Folder Name</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="folder-list folder-list-included">
|
||||
<div class="sidebar-left-h2">Included chats</div>
|
||||
<div class="folder-categories">
|
||||
<div class="folder-category-button blue tgico-add rp"><p>Add Chats</p></div>
|
||||
<div class="folder-category-button menu-contacts tgico-group"><p>Contacts</p></div>
|
||||
<div class="folder-category-button menu-non_contacts tgico-noncontacts"><p>Non-Contacts</p></div>
|
||||
<div class="folder-category-button menu-groups tgico-group"><p>Groups</p></div>
|
||||
<div class="folder-category-button menu-broadcasts tgico-channel"><p>Channels</p></div>
|
||||
<div class="folder-category-button menu-bots tgico-bots"><p>Bots</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="folder-list folder-list-excluded">
|
||||
<div class="sidebar-left-h2">Excluded chats</div>
|
||||
<div class="folder-categories">
|
||||
<div class="folder-category-button blue tgico-minus rp"><p>Remove Chats</p></div>
|
||||
<div class="folder-category-button menu-exclude_muted tgico-mute"><p>Muted</p></div>
|
||||
<div class="folder-category-button menu-exclude_archived tgico-archive"><p>Archived</p></div>
|
||||
<div class="folder-category-button menu-exclude_read tgico-readchats"><p>Read</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-slider-item included-chats-container">
|
||||
<div class="sidebar-header">
|
||||
<button class="btn-icon rp tgico-back sidebar-close-button"></button>
|
||||
<div class="sidebar-header__title"></div>
|
||||
<div class="btn-icon tgico-check1 btn-confirm rp" style="display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-menu" id="dialogs-contextmenu">
|
||||
<div class="btn-menu-item menu-unread tgico rp"></div>
|
||||
|
@ -1,16 +1,17 @@
|
||||
import { findUpClassName, $rootScope, escapeRegExp, whichChild, findUpTag, cancelEvent, formatNumber } from "../utils";
|
||||
import appImManager, { AppImManager } from "./appImManager";
|
||||
import appPeersManager from './appPeersManager';
|
||||
import appMessagesManager, { AppMessagesManager, Dialog } from "./appMessagesManager";
|
||||
import appMessagesManager, { AppMessagesManager, Dialog, DialogFilter } from "./appMessagesManager";
|
||||
import appUsersManager, { User } from "./appUsersManager";
|
||||
import { RichTextProcessor } from "../richtextprocessor";
|
||||
import { ripple, putPreloader, positionMenu, openBtnMenu, parseMenuButtonsTo } from "../../components/misc";
|
||||
import { ripple, putPreloader, positionMenu, openBtnMenu, parseMenuButtonsTo, horizontalMenu } from "../../components/misc";
|
||||
//import Scrollable from "../../components/scrollable";
|
||||
import Scrollable from "../../components/scrollable_new";
|
||||
import { logger } from "../polyfill";
|
||||
import { logger, LogLevels } from "../polyfill";
|
||||
import appChatsManager from "./appChatsManager";
|
||||
import AvatarElement from "../../components/avatar";
|
||||
import { PopupButton, PopupPeer } from "../../components/popup";
|
||||
import { SliderTab } from "../../components/slider";
|
||||
|
||||
type DialogDom = {
|
||||
avatarEl: AvatarElement,
|
||||
@ -39,106 +40,11 @@ class DialogsContextMenu {
|
||||
} = {} as any;
|
||||
private selectedID: number;
|
||||
private peerType: 'channel' | 'chat' | 'megagroup' | 'group' | 'saved';
|
||||
private filterID: number;
|
||||
|
||||
constructor(private attachTo: HTMLElement[]) {
|
||||
constructor() {
|
||||
parseMenuButtonsTo(this.buttons, this.element.children);
|
||||
|
||||
const onContextMenu = (e: MouseEvent) => {
|
||||
let li: HTMLDivElement = null;
|
||||
|
||||
try {
|
||||
li = findUpTag(e.target, 'LI');
|
||||
} catch(e) {}
|
||||
|
||||
if(!li) return;
|
||||
|
||||
e.preventDefault();
|
||||
if(this.element.classList.contains('active')) {
|
||||
return false;
|
||||
}
|
||||
e.cancelBubble = true;
|
||||
|
||||
this.selectedID = +li.getAttribute('data-peerID');
|
||||
const dialog = appMessagesManager.getDialogByPeerID(this.selectedID)[0];
|
||||
const notOurDialog = dialog.peerID != $rootScope.myID;
|
||||
|
||||
// archive button
|
||||
if(notOurDialog) {
|
||||
const button = this.buttons.archive;
|
||||
const condition = dialog.folder_id == 1;
|
||||
button.classList.toggle('flip-icon', condition);
|
||||
button.innerText = condition ? 'Unarchive' : 'Archive';
|
||||
this.buttons.archive.style.display = '';
|
||||
} else {
|
||||
this.buttons.archive.style.display = 'none';
|
||||
}
|
||||
|
||||
// pin button
|
||||
{
|
||||
const button = this.buttons.pin;
|
||||
const condition = dialog.pFlags?.pinned;
|
||||
button.classList.toggle('flip-icon', condition);
|
||||
button.innerText = condition ? 'Unpin' : 'Pin';
|
||||
}
|
||||
|
||||
// mute button
|
||||
if(notOurDialog) {
|
||||
const button = this.buttons.mute;
|
||||
const condition = dialog.notify_settings && dialog.notify_settings.mute_until > (Date.now() / 1000 | 0);
|
||||
button.classList.toggle('flip-icon', condition);
|
||||
button.innerText = condition ? 'Unmute' : 'Mute';
|
||||
this.buttons.mute.style.display = '';
|
||||
} else {
|
||||
this.buttons.mute.style.display = 'none';
|
||||
}
|
||||
|
||||
// unread button
|
||||
{
|
||||
const button = this.buttons.unread;
|
||||
const condition = !!(dialog.pFlags?.unread_mark || dialog.unread_count);
|
||||
button.classList.toggle('flip-icon', condition);
|
||||
button.innerText = condition ? 'Mark as Read' : 'Mark as Unread';
|
||||
}
|
||||
|
||||
/* // clear history button
|
||||
if(appPeersManager.isChannel(this.selectedID)) {
|
||||
this.buttons.clear.style.display = 'none';
|
||||
} else {
|
||||
this.buttons.clear.style.display = '';
|
||||
} */
|
||||
|
||||
// delete button
|
||||
let deleteButtonText = '';
|
||||
if(appPeersManager.isMegagroup(this.selectedID)) {
|
||||
deleteButtonText = 'Leave';
|
||||
//deleteButtonText = 'Leave group';
|
||||
this.peerType = 'megagroup';
|
||||
} else if(appPeersManager.isChannel(this.selectedID)) {
|
||||
deleteButtonText = 'Leave';
|
||||
//deleteButtonText = 'Leave channel';
|
||||
this.peerType = 'channel';
|
||||
} else if(this.selectedID < 0) {
|
||||
deleteButtonText = 'Delete';
|
||||
//deleteButtonText = 'Delete and leave';
|
||||
this.peerType = 'group';
|
||||
} else {
|
||||
deleteButtonText = 'Delete';
|
||||
//deleteButtonText = 'Delete chat';
|
||||
this.peerType = this.selectedID == $rootScope.myID ? 'saved' : 'chat';
|
||||
}
|
||||
this.buttons.delete.innerText = deleteButtonText;
|
||||
|
||||
li.classList.add('menu-open');
|
||||
positionMenu(e, this.element);
|
||||
openBtnMenu(this.element, () => {
|
||||
li.classList.remove('menu-open');
|
||||
});
|
||||
};
|
||||
|
||||
this.attachTo.forEach(el => {
|
||||
el.addEventListener('contextmenu', onContextMenu);
|
||||
});
|
||||
|
||||
this.buttons.archive.addEventListener('click', () => {
|
||||
let dialog = appMessagesManager.getDialogByPeerID(this.selectedID)[0];
|
||||
if(dialog) {
|
||||
@ -147,7 +53,7 @@ class DialogsContextMenu {
|
||||
});
|
||||
|
||||
this.buttons.pin.addEventListener('click', () => {
|
||||
appMessagesManager.toggleDialogPin(this.selectedID);
|
||||
appMessagesManager.toggleDialogPin(this.selectedID, this.filterID);
|
||||
});
|
||||
|
||||
this.buttons.mute.addEventListener('click', () => {
|
||||
@ -255,11 +161,159 @@ class DialogsContextMenu {
|
||||
popup.show();
|
||||
});
|
||||
}
|
||||
|
||||
onContextMenu = (e: MouseEvent) => {
|
||||
let li: HTMLDivElement = null;
|
||||
|
||||
try {
|
||||
li = findUpTag(e.target, 'LI');
|
||||
} catch(e) {}
|
||||
|
||||
if(!li) return;
|
||||
|
||||
e.preventDefault();
|
||||
if(this.element.classList.contains('active')) {
|
||||
return false;
|
||||
}
|
||||
e.cancelBubble = true;
|
||||
|
||||
this.filterID = appDialogsManager.filterID;
|
||||
|
||||
this.selectedID = +li.getAttribute('data-peerID');
|
||||
const dialog = appMessagesManager.getDialogByPeerID(this.selectedID)[0];
|
||||
const notOurDialog = dialog.peerID != $rootScope.myID;
|
||||
|
||||
// archive button
|
||||
if(notOurDialog) {
|
||||
const button = this.buttons.archive;
|
||||
const condition = dialog.folder_id == 1;
|
||||
button.classList.toggle('flip-icon', condition);
|
||||
button.innerText = condition ? 'Unarchive' : 'Archive';
|
||||
this.buttons.archive.style.display = '';
|
||||
} else {
|
||||
this.buttons.archive.style.display = 'none';
|
||||
}
|
||||
|
||||
// pin button
|
||||
{
|
||||
const button = this.buttons.pin;
|
||||
//const condition = !!dialog.pFlags?.pinned;
|
||||
const condition = this.filterID > 1 ? appMessagesManager.filtersStorage.filters[this.filterID].pinned_peers.includes(dialog.peerID) : !!dialog.pFlags?.pinned;
|
||||
button.classList.toggle('flip-icon', condition);
|
||||
button.innerText = condition ? 'Unpin' : 'Pin';
|
||||
}
|
||||
|
||||
// mute button
|
||||
if(notOurDialog) {
|
||||
const button = this.buttons.mute;
|
||||
const condition = dialog.notify_settings && dialog.notify_settings.mute_until > (Date.now() / 1000 | 0);
|
||||
button.classList.toggle('flip-icon', condition);
|
||||
button.innerText = condition ? 'Unmute' : 'Mute';
|
||||
this.buttons.mute.style.display = '';
|
||||
} else {
|
||||
this.buttons.mute.style.display = 'none';
|
||||
}
|
||||
|
||||
// unread button
|
||||
{
|
||||
const button = this.buttons.unread;
|
||||
const condition = !!(dialog.pFlags?.unread_mark || dialog.unread_count);
|
||||
button.classList.toggle('flip-icon', condition);
|
||||
button.innerText = condition ? 'Mark as Read' : 'Mark as Unread';
|
||||
}
|
||||
|
||||
/* // clear history button
|
||||
if(appPeersManager.isChannel(this.selectedID)) {
|
||||
this.buttons.clear.style.display = 'none';
|
||||
} else {
|
||||
this.buttons.clear.style.display = '';
|
||||
} */
|
||||
|
||||
// delete button
|
||||
let deleteButtonText = '';
|
||||
if(appPeersManager.isMegagroup(this.selectedID)) {
|
||||
deleteButtonText = 'Leave';
|
||||
//deleteButtonText = 'Leave group';
|
||||
this.peerType = 'megagroup';
|
||||
} else if(appPeersManager.isChannel(this.selectedID)) {
|
||||
deleteButtonText = 'Leave';
|
||||
//deleteButtonText = 'Leave channel';
|
||||
this.peerType = 'channel';
|
||||
} else if(this.selectedID < 0) {
|
||||
deleteButtonText = 'Delete';
|
||||
//deleteButtonText = 'Delete and leave';
|
||||
this.peerType = 'group';
|
||||
} else {
|
||||
deleteButtonText = 'Delete';
|
||||
//deleteButtonText = 'Delete chat';
|
||||
this.peerType = this.selectedID == $rootScope.myID ? 'saved' : 'chat';
|
||||
}
|
||||
this.buttons.delete.innerText = deleteButtonText;
|
||||
|
||||
li.classList.add('menu-open');
|
||||
positionMenu(e, this.element);
|
||||
openBtnMenu(this.element, () => {
|
||||
li.classList.remove('menu-open');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export class AppArchivedTab implements SliderTab {
|
||||
public container = document.getElementById('chats-archived-container') as HTMLDivElement;
|
||||
public chatList = document.getElementById('dialogs-archived') as HTMLUListElement;
|
||||
public scroll: Scrollable = null;
|
||||
public loadedAll: boolean;
|
||||
public loadDialogsPromise: Promise<any>;
|
||||
public wasFilterID: number;
|
||||
|
||||
init() {
|
||||
this.scroll = new Scrollable(this.container, 'y', 'CLA', this.chatList, 500);
|
||||
this.scroll.setVirtualContainer(this.chatList);
|
||||
this.scroll.onScrolledBottom = appDialogsManager.onChatsScroll;
|
||||
///this.scroll.attachSentinels();
|
||||
|
||||
appDialogsManager.setListClickListener(this.chatList);
|
||||
this.chatList.addEventListener('contextmenu', appDialogsManager.contextMenu.onContextMenu);
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
setTimeout(appDialogsManager.onChatsScroll, 0);
|
||||
});
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
if(this.init) {
|
||||
this.init();
|
||||
this.init = null;
|
||||
}
|
||||
|
||||
this.wasFilterID = appDialogsManager.filterID;
|
||||
appDialogsManager.scroll = this.scroll;
|
||||
appDialogsManager.filterID = 1;
|
||||
appDialogsManager.onTabChange();
|
||||
}
|
||||
|
||||
// вообще, так делать нельзя, но нет времени чтобы переделать главный чатлист на слайд...
|
||||
onOpenAfterTimeout() {
|
||||
appDialogsManager.chatLists[this.wasFilterID].innerHTML = '';
|
||||
}
|
||||
|
||||
onClose() {
|
||||
appDialogsManager.scroll = appDialogsManager._scroll;
|
||||
appDialogsManager.filterID = this.wasFilterID;
|
||||
appDialogsManager.onTabChange();
|
||||
}
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
this.chatList.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
export const archivedTab = new AppArchivedTab();
|
||||
|
||||
export class AppDialogsManager {
|
||||
public chatList = document.getElementById('dialogs') as HTMLUListElement;
|
||||
public chatListArchived = document.getElementById('dialogs-archived') as HTMLUListElement;
|
||||
public _chatList = document.getElementById('dialogs') as HTMLUListElement;
|
||||
public chatList = this._chatList;
|
||||
|
||||
public pinnedDelimiter: HTMLDivElement;
|
||||
/* public chatsHidden: Scrollable["hiddenElements"];
|
||||
public chatsVisible: Scrollable["visibleElements"];
|
||||
@ -267,51 +321,58 @@ export class AppDialogsManager {
|
||||
public chatsArchivedVisible: Scrollable["visibleElements"]; */
|
||||
|
||||
public doms: {[peerID: number]: DialogDom} = {};
|
||||
public domsArchived: {[peerID: number]: DialogDom} = {};
|
||||
public lastActiveListElement: HTMLElement = null;
|
||||
|
||||
/* private rippleCallback: (value?: boolean | PromiseLike<boolean>) => void = null;
|
||||
private lastClickID = 0;
|
||||
private lastGoodClickID = 0; */
|
||||
|
||||
public chatsArchivedContainer = document.getElementById('chats-archived-container') as HTMLDivElement;
|
||||
public chatsContainer = document.getElementById('chats-container') as HTMLDivElement;
|
||||
private chatsPreloader: HTMLDivElement;
|
||||
//private chatsLoadCount = 0;
|
||||
//private loadDialogsPromise: Promise<any>;
|
||||
private loadDialogsPromise: ReturnType<AppMessagesManager["getConversations"]>;
|
||||
|
||||
private loadedAll = false;
|
||||
private loadedArchivedAll = false;
|
||||
public loadDialogsPromise: ReturnType<AppMessagesManager["getConversations"]>;
|
||||
public loadedAll = false;
|
||||
|
||||
public scroll: Scrollable = null;
|
||||
public scrollArchived: Scrollable = null;
|
||||
public _scroll: Scrollable = null;
|
||||
|
||||
private log = logger('DIALOGS', LogLevels.log | LogLevels.error | LogLevels.warn | LogLevels.debug);
|
||||
|
||||
private log = logger('DIALOGS');
|
||||
public contextMenu = new DialogsContextMenu();
|
||||
|
||||
private contextMenu = new DialogsContextMenu([this.chatList, this.chatListArchived]);
|
||||
public chatLists: {[filterID: number]: HTMLUListElement} = {
|
||||
0: this.chatList,
|
||||
1: archivedTab.chatList
|
||||
};
|
||||
public filterID = 0;
|
||||
private folders: {[k in 'menu' | 'container']: HTMLElement} = {
|
||||
menu: document.getElementById('folders-tabs'),
|
||||
container: document.getElementById('folders-container')
|
||||
};
|
||||
private filtersRendered: {
|
||||
[filterID: string]: {
|
||||
menu: HTMLElement, container: HTMLElement
|
||||
}
|
||||
} = {};
|
||||
|
||||
private debug = false;
|
||||
private accumulateArchivedTimeout: number;
|
||||
|
||||
constructor() {
|
||||
this.chatList.addEventListener('contextmenu', this.contextMenu.onContextMenu);
|
||||
this.chatsPreloader = putPreloader(null, true);
|
||||
|
||||
this.pinnedDelimiter = document.createElement('div');
|
||||
this.pinnedDelimiter.classList.add('pinned-delimiter');
|
||||
this.pinnedDelimiter.appendChild(document.createElement('span'));
|
||||
if(USEPINNEDDELIMITER) {
|
||||
this.pinnedDelimiter = document.createElement('div');
|
||||
this.pinnedDelimiter.classList.add('pinned-delimiter');
|
||||
this.pinnedDelimiter.appendChild(document.createElement('span'));
|
||||
}
|
||||
|
||||
this.scroll = new Scrollable(this.chatsContainer, 'y', 'CL', this.chatList, 500);
|
||||
this.scroll = this._scroll = new Scrollable(this.chatsContainer, 'y', 'CL', this.chatList, 500);
|
||||
this.scroll.onScrolledBottom = this.onChatsScroll;
|
||||
this.scroll.setVirtualContainer(this.chatList);
|
||||
this.scroll.onScrolledBottom = this.onChatsScroll.bind(this);
|
||||
//this.scroll.attachSentinels();
|
||||
|
||||
this.scrollArchived = new Scrollable(this.chatsArchivedContainer, 'y', 'CLA', this.chatListArchived, 500);
|
||||
this.scrollArchived.setVirtualContainer(this.chatListArchived);
|
||||
this.scrollArchived.onScrolledBottom = this.onChatsArchivedScroll.bind(this);
|
||||
///this.scroll.attachSentinels();
|
||||
|
||||
this.setListClickListener(this.chatList);
|
||||
this.setListClickListener(this.chatListArchived);
|
||||
|
||||
if(testScroll) {
|
||||
let i = 0;
|
||||
@ -329,14 +390,6 @@ export class AppDialogsManager {
|
||||
(window as any).addElement = add;
|
||||
}
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
//this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5);
|
||||
|
||||
setTimeout(() => {
|
||||
this.onChatsArchivedScroll();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$rootScope.$on('user_update', (e: CustomEvent) => {
|
||||
let userID = e.detail;
|
||||
|
||||
@ -377,26 +430,20 @@ export class AppDialogsManager {
|
||||
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
||||
if(dialog) {
|
||||
this.setLastMessage(dialog);
|
||||
this.validateForFilter();
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('dialogs_multiupdate', (e: CustomEvent) => {
|
||||
let dialogs = e.detail;
|
||||
const dialogs = e.detail;
|
||||
|
||||
for(let id in dialogs) {
|
||||
let dialog = dialogs[id];
|
||||
|
||||
/////console.log('updating dialog:', dialog);
|
||||
|
||||
if(!(dialog.peerID in this.doms)) {
|
||||
this.addDialog(dialog);
|
||||
}
|
||||
|
||||
this.setLastMessage(dialog);
|
||||
this.setDialogPosition(dialog);
|
||||
for(const id in dialogs) {
|
||||
const dialog = dialogs[id];
|
||||
this.updateDialog(dialog);
|
||||
}
|
||||
|
||||
this.setPinnedDelimiter();
|
||||
this.validateForFilter();
|
||||
});
|
||||
|
||||
$rootScope.$on('dialog_drop', (e: CustomEvent) => {
|
||||
@ -406,7 +453,7 @@ export class AppDialogsManager {
|
||||
if(dom) {
|
||||
dom.listEl.remove();
|
||||
delete this.doms[peerID];
|
||||
(dialog.folder_id == 1 ? this.scrollArchived : this.scroll).reorder();
|
||||
this.scroll.reorder();
|
||||
}
|
||||
});
|
||||
|
||||
@ -423,6 +470,8 @@ export class AppDialogsManager {
|
||||
if(dialog.peerID == $rootScope.selectedPeerID) {
|
||||
appImManager.updateUnreadByDialog(dialog);
|
||||
}
|
||||
|
||||
this.validateForFilter();
|
||||
}
|
||||
});
|
||||
|
||||
@ -444,29 +493,190 @@ export class AppDialogsManager {
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('filter_update', (e: CustomEvent) => {
|
||||
const filter: DialogFilter = e.detail;
|
||||
if(!this.filtersRendered[filter.id]) {
|
||||
this.addFilter(filter);
|
||||
} else if(filter.id == this.filterID) { // это нет тут смысла вызывать, так как будет dialogs_multiupdate
|
||||
//this.validateForFilter();
|
||||
const folder = appMessagesManager.dialogsStorage.getFolder(filter.id);
|
||||
this.validateForFilter();
|
||||
for(let i = 0, length = folder.length; i < length; ++i) {
|
||||
const dialog = folder[i];
|
||||
this.updateDialog(dialog);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('filter_delete', (e: CustomEvent) => {
|
||||
const filter: DialogFilter = e.detail;
|
||||
const elements = this.filtersRendered[filter.id];
|
||||
if(!elements) return;
|
||||
|
||||
// set tab
|
||||
//(this.folders.menu.firstElementChild.children[Math.max(0, filter.id - 2)] as HTMLElement).click();
|
||||
(this.folders.menu.firstElementChild.children[0] as HTMLElement).click();
|
||||
|
||||
elements.container.remove();
|
||||
elements.menu.remove();
|
||||
|
||||
delete this.chatLists[filter.id];
|
||||
delete this.filtersRendered[filter.id];
|
||||
|
||||
if(!Object.keys(this.filtersRendered).length) {
|
||||
this.folders.menu.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
/* $rootScope.$on('filter_pinned_order', (e: CustomEvent) => {
|
||||
const {order, id} = e.detail as {order: number[], id: number};
|
||||
if(this.prevTabID != id) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(const peerID of order) {
|
||||
this.updateDialog(appMessagesManager.getDialogByPeerID(peerID)[0]);
|
||||
}
|
||||
}); */
|
||||
|
||||
new Scrollable(this.folders.menu.parentElement, 'x');
|
||||
const selectTab = horizontalMenu(this.folders.menu, this.folders.container, (id, tabContent) => {
|
||||
/* if(id != 0) {
|
||||
id += 1;
|
||||
} */
|
||||
|
||||
id = +tabContent.dataset.filterID || 0;
|
||||
|
||||
if(this.filterID == id) return;
|
||||
|
||||
this.scroll.setVirtualContainer(this.chatLists[id]);
|
||||
this.filterID = id;
|
||||
this.onTabChange();
|
||||
}, () => {
|
||||
for(const folderID in this.chatLists) {
|
||||
if(+folderID != this.filterID) {
|
||||
this.chatLists[folderID].innerHTML = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//selectTab(0);
|
||||
(this.folders.menu.firstElementChild.firstElementChild as HTMLElement).click();
|
||||
|
||||
/* false && */appMessagesManager.loadSavedState().then(() => {
|
||||
this.loadDialogs().then(result => {
|
||||
this.setPinnedDelimiter();
|
||||
//appSidebarLeft.onChatsScroll();
|
||||
this.loadDialogs(true);
|
||||
});
|
||||
return appMessagesManager.filtersStorage.getDialogFilters();
|
||||
}).then(filters => {
|
||||
for(const filterID in filters) {
|
||||
this.addFilter(filters[filterID]);
|
||||
}
|
||||
|
||||
return this.loadDialogs(this.filterID);
|
||||
}).then(result => {
|
||||
this.setPinnedDelimiter();
|
||||
//appSidebarLeft.onChatsScroll();
|
||||
this.loadDialogs(1);
|
||||
});
|
||||
}
|
||||
|
||||
public async loadDialogs(archived = false) {
|
||||
private updateDialog(dialog: Dialog) {
|
||||
if(!dialog) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.doms.hasOwnProperty(dialog.peerID)) {
|
||||
this.addDialog(dialog);
|
||||
}
|
||||
|
||||
if(this.getDialogDom(dialog.peerID)) {
|
||||
this.setLastMessage(dialog);
|
||||
this.setDialogPosition(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
onTabChange = () => {
|
||||
this.doms = {};
|
||||
this.loadedAll = false;
|
||||
this.lastActiveListElement = null;
|
||||
this.chatList = this.chatLists[this.filterID];
|
||||
this.loadDialogs(this.filterID);
|
||||
};
|
||||
|
||||
/**
|
||||
* Удалит неподходящие чаты из списка, но не добавит их(!)
|
||||
*/
|
||||
public validateForFilter() {
|
||||
if(this.filterID == 0) return;
|
||||
|
||||
const folder = appMessagesManager.dialogsStorage.getFolder(this.filterID);
|
||||
let affected = false;
|
||||
for(const _peerID in this.doms) {
|
||||
const peerID = +_peerID;
|
||||
|
||||
// если больше не подходит по фильтру, удаляем
|
||||
if(folder.findIndex((dialog) => dialog.peerID == peerID) === -1) {
|
||||
const listEl = this.doms[peerID].listEl;
|
||||
listEl.remove();
|
||||
affected = true;
|
||||
|
||||
if(this.lastActiveListElement == listEl) {
|
||||
this.lastActiveListElement = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(affected) {
|
||||
this.scroll.reorder();
|
||||
}
|
||||
}
|
||||
|
||||
public addFilter(filter: DialogFilter) {
|
||||
if(this.filtersRendered[filter.id]) return;
|
||||
|
||||
const li = document.createElement('li');
|
||||
const span = document.createElement('span');
|
||||
span.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);
|
||||
li.append(span);
|
||||
ripple(li);
|
||||
|
||||
this.folders.menu.firstElementChild.append(li);
|
||||
|
||||
const ul = document.createElement('ul');
|
||||
const div = document.createElement('div');
|
||||
div.append(ul);
|
||||
div.dataset.filterID = '' + filter.id;
|
||||
this.folders.container.append(div);
|
||||
|
||||
this.chatLists[filter.id] = ul;
|
||||
this.setListClickListener(ul);
|
||||
ul.addEventListener('contextmenu', this.contextMenu.onContextMenu);
|
||||
|
||||
setTimeout(() => {
|
||||
this.folders.menu.style.display = '';
|
||||
}, 0);
|
||||
|
||||
this.filtersRendered[filter.id] = {
|
||||
menu: li,
|
||||
container: div
|
||||
};
|
||||
}
|
||||
|
||||
public async loadDialogs(folderID: number) {
|
||||
if(testScroll) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.loadDialogsPromise/* || 1 == 1 */) return this.loadDialogsPromise;
|
||||
|
||||
(archived ? this.chatsArchivedContainer : this.chatsContainer).append(this.chatsPreloader);
|
||||
if(!this.chatList.childElementCount) {
|
||||
const container = this.chatList.parentElement;
|
||||
container.append(this.chatsPreloader);
|
||||
}
|
||||
|
||||
let storage = appMessagesManager.dialogsStorage[+archived] || [];
|
||||
const storage = appMessagesManager.dialogsStorage.getFolder(folderID);
|
||||
let offsetIndex = 0;
|
||||
|
||||
for(let i = storage.length - 1; i >= 0; --i) {
|
||||
let dialog = storage[i];
|
||||
const dialog = storage[i];
|
||||
if(this.getDialogDom(dialog.peerID)) {
|
||||
offsetIndex = dialog.index;
|
||||
break;
|
||||
@ -477,10 +687,10 @@ export class AppDialogsManager {
|
||||
try {
|
||||
//console.time('getDialogs time');
|
||||
|
||||
let loadCount = 50/*this.chatsLoadCount */;
|
||||
this.loadDialogsPromise = appMessagesManager.getConversations('', offsetIndex, loadCount, +archived);
|
||||
const loadCount = 50/*this.chatsLoadCount */;
|
||||
this.loadDialogsPromise = appMessagesManager.getConversations('', offsetIndex, loadCount, folderID);
|
||||
|
||||
let result = await this.loadDialogsPromise;
|
||||
const result = await this.loadDialogsPromise;
|
||||
|
||||
//console.timeEnd('getDialogs time');
|
||||
|
||||
@ -490,12 +700,11 @@ export class AppDialogsManager {
|
||||
});
|
||||
}
|
||||
|
||||
if(!result.dialogs.length || (archived ? this.scrollArchived.length == result.count : this.scroll.length == result.count)) { // loaded all
|
||||
if(archived) this.loadedArchivedAll = true;
|
||||
else this.loadedAll = true;
|
||||
if(!result.dialogs.length || this.chatList.childElementCount == result.count) { // loaded all
|
||||
this.loadedAll = true;
|
||||
}
|
||||
|
||||
this.debug && this.log('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, this.scroll.length, archived);
|
||||
this.log.debug('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, this.chatList.childElementCount);
|
||||
this.scroll.onScroll();
|
||||
} catch(err) {
|
||||
this.log.error(err);
|
||||
@ -505,18 +714,10 @@ export class AppDialogsManager {
|
||||
this.loadDialogsPromise = undefined;
|
||||
}
|
||||
|
||||
public onChatsScroll() {
|
||||
onChatsScroll = () => {
|
||||
if(this.loadedAll || this.loadDialogsPromise) return;
|
||||
|
||||
this.log('onChatsScroll');
|
||||
|
||||
this.loadDialogs();
|
||||
}
|
||||
|
||||
public onChatsArchivedScroll() {
|
||||
if(this.loadedArchivedAll || this.loadDialogsPromise) return;
|
||||
|
||||
this.loadDialogs(true);
|
||||
this.loadDialogs(this.filterID);
|
||||
}
|
||||
|
||||
public setListClickListener(list: HTMLUListElement, onFound?: () => void) {
|
||||
@ -564,13 +765,21 @@ export class AppDialogsManager {
|
||||
}, {capture: true});
|
||||
}
|
||||
|
||||
public setDialogPosition(dialog: Dialog) {
|
||||
let pos = appMessagesManager.getDialogByPeerID(dialog.peerID)[1];
|
||||
let dom = this.getDialogDom(dialog.peerID);
|
||||
public setDialogPosition(dialog: Dialog, pos?: number) {
|
||||
const dom = this.getDialogDom(dialog.peerID);
|
||||
if(!dom) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(pos === undefined) {
|
||||
pos = appMessagesManager.dialogsStorage.getDialog(dialog.peerID, this.filterID)[1];
|
||||
}
|
||||
|
||||
let prevPos = whichChild(dom.listEl);
|
||||
|
||||
let wrongFolder = (dialog.folder_id == 1 && this.chatList == dom.listEl.parentElement) || (dialog.folder_id == 0 && this.chatListArchived == dom.listEl.parentElement);
|
||||
if(wrongFolder) prevPos = 0xFFFF;
|
||||
/* let wrongFolder = (dialog.folder_id == 1 && this.chatList == dom.listEl.parentElement) || (dialog.folder_id == 0 && this.chatListArchived == dom.listEl.parentElement);
|
||||
let wrongFolder = false;
|
||||
if(wrongFolder) prevPos = 0xFFFF; */
|
||||
|
||||
if(prevPos == pos) {
|
||||
return;
|
||||
@ -578,23 +787,23 @@ export class AppDialogsManager {
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
let chatList = dialog.folder_id == 1 ? this.chatListArchived : this.chatList;
|
||||
const chatList = this.chatList;
|
||||
if(chatList.childElementCount > pos) {
|
||||
chatList.insertBefore(dom.listEl, chatList.children[pos]);
|
||||
} else {
|
||||
chatList.append(dom.listEl);
|
||||
}
|
||||
|
||||
(dialog.folder_id == 1 ? this.scrollArchived : this.scroll).reorder();
|
||||
this.scroll.reorder();
|
||||
|
||||
this.debug && this.log('setDialogPosition:', dialog, dom, pos);
|
||||
this.log.debug('setDialogPosition:', dialog, dom, pos);
|
||||
}
|
||||
|
||||
public setPinnedDelimiter() {
|
||||
if(!USEPINNEDDELIMITER) return;
|
||||
|
||||
let index = -1;
|
||||
let dialogs = appMessagesManager.dialogsStorage[0];
|
||||
let dialogs = appMessagesManager.dialogsStorage.getFolder(0);
|
||||
for(let dialog of dialogs) {
|
||||
if(dialog.pFlags?.pinned) {
|
||||
index++;
|
||||
@ -731,7 +940,7 @@ export class AppDialogsManager {
|
||||
dom.lastTimeSpan.innerHTML = timeStr;
|
||||
} else dom.lastTimeSpan.innerHTML = '';
|
||||
|
||||
if((this.doms[peerID] || this.domsArchived[peerID]) == dom) {
|
||||
if(this.doms[peerID] == dom) {
|
||||
this.setUnreadMessages(dialog);
|
||||
} else { // means search
|
||||
dom.listEl.dataset.mid = lastMessage.mid;
|
||||
@ -739,18 +948,22 @@ export class AppDialogsManager {
|
||||
}
|
||||
|
||||
public setUnreadMessages(dialog: Dialog) {
|
||||
let dom = this.getDialogDom(dialog.peerID);
|
||||
const dom = this.getDialogDom(dialog.peerID);
|
||||
|
||||
if(dialog.folder_id == 1) {
|
||||
this.accumulateArchivedUnread();
|
||||
}
|
||||
|
||||
if(!dom) {
|
||||
this.log.error('setUnreadMessages no dom!', dialog);
|
||||
return;
|
||||
}
|
||||
|
||||
let lastMessage = appMessagesManager.getMessage(dialog.top_message);
|
||||
const lastMessage = appMessagesManager.getMessage(dialog.top_message);
|
||||
if(lastMessage._ != 'messageEmpty' && !lastMessage.deleted &&
|
||||
lastMessage.from_id == $rootScope.myID && lastMessage.peerID != $rootScope.myID &&
|
||||
dialog.read_outbox_max_id) { // maybe comment, 06.20.2020
|
||||
let outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread)
|
||||
const outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread)
|
||||
/* && dialog.read_outbox_max_id != 0 */; // maybe uncomment, 31.01.2020
|
||||
|
||||
//console.log('outgoing', outgoing, lastMessage);
|
||||
@ -766,34 +979,38 @@ export class AppDialogsManager {
|
||||
|
||||
dom.unreadMessagesSpan.innerText = '';
|
||||
dom.unreadMessagesSpan.classList.remove('tgico-pinnedchat');
|
||||
|
||||
const filter = appMessagesManager.filtersStorage.filters[this.filterID];
|
||||
let isPinned: boolean;
|
||||
if(filter) {
|
||||
isPinned = filter.pinned_peers.findIndex(peerID => peerID == dialog.peerID) !== -1;
|
||||
} else {
|
||||
isPinned = !!dialog.pFlags.pinned;
|
||||
}
|
||||
|
||||
if(dialog.unread_count || dialog.pFlags.unread_mark) {
|
||||
//dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count ? formatNumber(dialog.unread_count, 1) : ' ');
|
||||
dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count || ' ');
|
||||
//dom.unreadMessagesSpan.classList.remove('tgico-pinnedchat');
|
||||
dom.unreadMessagesSpan.classList.add(new Date(dialog.notify_settings?.mute_until * 1000) > new Date() ?
|
||||
dom.unreadMessagesSpan.classList.add((dialog.notify_settings?.mute_until * 1000) > Date.now() ?
|
||||
'unread-muted' : 'unread');
|
||||
} else if(dialog.pFlags.pinned && dialog.folder_id == 0) {
|
||||
} else if(isPinned) {
|
||||
dom.unreadMessagesSpan.classList.remove('unread', 'unread-muted');
|
||||
dom.unreadMessagesSpan.classList.add('tgico-pinnedchat');
|
||||
}
|
||||
}
|
||||
|
||||
// set archived new count
|
||||
if(dialog.folder_id == 1) {
|
||||
let sum = Object.keys(this.domsArchived).map(p => +p).reduce((acc: number, peerID: number) => {
|
||||
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
||||
if(dialog) {
|
||||
return acc + dialog.unread_count;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, 0);
|
||||
|
||||
public accumulateArchivedUnread() {
|
||||
if(this.accumulateArchivedTimeout) return;
|
||||
this.accumulateArchivedTimeout = setTimeout(() => {
|
||||
this.accumulateArchivedTimeout = 0;
|
||||
const dialogs = appMessagesManager.dialogsStorage.getFolder(1);
|
||||
const sum = dialogs.reduce((acc, dialog) => acc + dialog.unread_count, 0);
|
||||
$rootScope.$broadcast('dialogs_archived_unread', {count: sum});
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public getDialogDom(peerID: number) {
|
||||
return this.doms[peerID] || this.domsArchived[peerID];
|
||||
return this.doms[peerID];
|
||||
}
|
||||
|
||||
public addDialog(_dialog: Dialog | number, container?: HTMLUListElement | Scrollable, drawStatus = true, rippleEnabled = true, onlyFirstName = false, meAsSaved = true) {
|
||||
@ -815,7 +1032,14 @@ export class AppDialogsManager {
|
||||
|
||||
let peerID: number = dialog.peerID;
|
||||
|
||||
if((this.doms[peerID] || this.domsArchived[peerID]) && !container) return;
|
||||
if(!container) {
|
||||
if(this.doms[peerID]) return;
|
||||
|
||||
const filter = appMessagesManager.filtersStorage.filters[this.filterID];
|
||||
if((filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) || (!filter && this.filterID != dialog.folder_id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let title = appPeersManager.getPeerTitle(peerID, false, onlyFirstName);
|
||||
|
||||
@ -848,15 +1072,18 @@ export class AppDialogsManager {
|
||||
let titleSpan = document.createElement('span');
|
||||
titleSpan.classList.add('user-title');
|
||||
|
||||
if(peerID < 0) {
|
||||
let chat = appChatsManager.getChat(-peerID);
|
||||
if(chat && chat.pFlags && chat.pFlags.verified) {
|
||||
titleSpan.classList.add('is-verified');
|
||||
}
|
||||
} else {
|
||||
let user = appUsersManager.getUser(peerID);
|
||||
if(user && user.pFlags && user.pFlags.verified) {
|
||||
titleSpan.classList.add('is-verified');
|
||||
// в других случаях иконка верификации не нужна (а первый - это главные чатлисты)
|
||||
if(!container) {
|
||||
if(peerID < 0) {
|
||||
let chat = appChatsManager.getChat(-peerID);
|
||||
if(chat && chat.pFlags && chat.pFlags.verified) {
|
||||
titleSpan.classList.add('is-verified');
|
||||
}
|
||||
} else {
|
||||
let user = appUsersManager.getUser(peerID);
|
||||
if(user && user.pFlags && user.pFlags.verified) {
|
||||
titleSpan.classList.add('is-verified');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -932,14 +1159,20 @@ export class AppDialogsManager {
|
||||
listEl: li
|
||||
};
|
||||
|
||||
if(!container) {
|
||||
if(dialog.folder_id && dialog.folder_id == 1) {
|
||||
this.scrollArchived.append(li);
|
||||
this.domsArchived[dialog.peerID] = dom;
|
||||
} else {
|
||||
this.scroll.append(li);
|
||||
this.doms[dialog.peerID] = dom;
|
||||
/* let good = false;
|
||||
for(const folderID in this.chatLists) {
|
||||
if(this.chatLists[folderID] == container) {
|
||||
good = true;
|
||||
}
|
||||
} */
|
||||
if(!container/* || good */) {
|
||||
this.scroll.append(li);
|
||||
|
||||
this.doms[dialog.peerID] = dom;
|
||||
|
||||
/* if(container) {
|
||||
container.append(li);
|
||||
} */
|
||||
|
||||
this.setLastMessage(dialog);
|
||||
} else {
|
||||
@ -950,7 +1183,10 @@ export class AppDialogsManager {
|
||||
}
|
||||
|
||||
public setTyping(dialog: Dialog, user: User) {
|
||||
let dom = this.getDialogDom(dialog.peerID);
|
||||
const dom = this.getDialogDom(dialog.peerID);
|
||||
if(!dom) {
|
||||
return;
|
||||
}
|
||||
|
||||
let str = '';
|
||||
if(dialog.peerID < 0) {
|
||||
@ -959,7 +1195,7 @@ export class AppDialogsManager {
|
||||
str = s + ' ';
|
||||
}
|
||||
|
||||
let senderBold = document.createElement('i');
|
||||
const senderBold = document.createElement('i');
|
||||
str += 'typing...';
|
||||
senderBold.innerHTML = str;
|
||||
|
||||
@ -969,10 +1205,15 @@ export class AppDialogsManager {
|
||||
}
|
||||
|
||||
public unsetTyping(dialog: Dialog) {
|
||||
let dom = this.getDialogDom(dialog.peerID);
|
||||
const dom = this.getDialogDom(dialog.peerID);
|
||||
if(!dom) {
|
||||
return;
|
||||
}
|
||||
|
||||
dom.lastMessageSpan.classList.remove('user-typing');
|
||||
this.setLastMessage(dialog, null, dom);
|
||||
}
|
||||
}
|
||||
|
||||
export default new AppDialogsManager();
|
||||
const appDialogsManager = new AppDialogsManager();
|
||||
export default appDialogsManager;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -97,13 +97,14 @@ const AppPeersManager = {
|
||||
},
|
||||
|
||||
getPeerID: (peerString: any): number => {
|
||||
if(isObject(peerString)) {
|
||||
if(typeof(peerString) === 'number') return peerString;
|
||||
else if(isObject(peerString)) {
|
||||
return peerString.user_id
|
||||
? peerString.user_id
|
||||
: -(peerString.channel_id || peerString.chat_id);
|
||||
} else if(!peerString) return 0;
|
||||
let isUser = peerString.charAt(0) == 'u';
|
||||
let peerParams = peerString.substr(1).split('_');
|
||||
const isUser = peerString.charAt(0) == 'u';
|
||||
const peerParams = peerString.substr(1).split('_');
|
||||
|
||||
return isUser ? peerParams[0] : -peerParams[0] || 0;
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
//import { logger } from "../polyfill";
|
||||
import appDialogsManager from "./appDialogsManager";
|
||||
import appDialogsManager, { AppArchivedTab, archivedTab } from "./appDialogsManager";
|
||||
import { $rootScope } from "../utils";
|
||||
import appImManager from "./appImManager";
|
||||
import AppSearch, { SearchGroup } from "../../components/appSearch";
|
||||
@ -14,6 +14,9 @@ import AppContactsTab from "../../components/sidebarLeft/contacts";
|
||||
import AppNewGroupTab from "../../components/sidebarLeft/newGroup";
|
||||
import AppSettingsTab from "../../components/sidebarLeft/settings";
|
||||
import AppEditProfileTab from "../../components/sidebarLeft/editProfile";
|
||||
import AppChatFoldersTab from "../../components/sidebarLeft/chatFolders";
|
||||
import AppEditFolderTab from "../../components/sidebarLeft/editFolder";
|
||||
import AppIncludedChatsTab from "../../components/sidebarLeft/includedChats";
|
||||
import SidebarSlider from "../../components/slider";
|
||||
import SearchInput from "../../components/searchInput";
|
||||
|
||||
@ -25,6 +28,9 @@ const contactsTab = new AppContactsTab();
|
||||
const newGroupTab = new AppNewGroupTab();
|
||||
const settingsTab = new AppSettingsTab();
|
||||
const editProfileTab = new AppEditProfileTab();
|
||||
const chatFoldersTab = new AppChatFoldersTab();
|
||||
const editFolderTab = new AppEditFolderTab();
|
||||
const includedChatsTab = new AppIncludedChatsTab();
|
||||
|
||||
export class AppSidebarLeft extends SidebarSlider {
|
||||
public static SLIDERITEMSIDS = {
|
||||
@ -35,6 +41,9 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
newGroup: 5,
|
||||
settings: 6,
|
||||
editProfile: 7,
|
||||
chatFolders: 8,
|
||||
editFolder: 9,
|
||||
includedChats: 10,
|
||||
};
|
||||
|
||||
private toolsBtn: HTMLButtonElement;
|
||||
@ -61,17 +70,21 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
privateChat: HTMLButtonElement,
|
||||
} = {} as any;
|
||||
|
||||
public archivedTab: AppArchivedTab;
|
||||
public newChannelTab: AppNewChannelTab;
|
||||
public addMembersTab: AppAddMembersTab;
|
||||
public contactsTab: AppContactsTab;
|
||||
public newGroupTab: AppNewGroupTab;
|
||||
public settingsTab: AppSettingsTab;
|
||||
public editProfileTab: AppEditProfileTab;
|
||||
public chatFoldersTab: AppChatFoldersTab;
|
||||
public editFolderTab: AppEditFolderTab;
|
||||
public includedChatsTab: AppIncludedChatsTab;
|
||||
|
||||
//private log = logger('SL');
|
||||
|
||||
private searchGroups = {
|
||||
contacts: new SearchGroup('Contacts and Chats', 'contacts'),
|
||||
contacts: new SearchGroup('Chats', 'contacts'),
|
||||
globalContacts: new SearchGroup('Global Search', 'contacts'),
|
||||
messages: new SearchGroup('Global Search', 'messages'),
|
||||
people: new SearchGroup('People', 'contacts', false, 'search-group-people'),
|
||||
@ -81,13 +94,16 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
|
||||
constructor() {
|
||||
super(document.getElementById('column-left') as HTMLDivElement, {
|
||||
//[AppSidebarLeft.SLIDERITEMSIDS.archived]: ,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.archived]: archivedTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.newChannel]: newChannelTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.contacts]: contactsTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.addMembers]: addMembersTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.newGroup]: newGroupTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.settings]: settingsTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.editProfile]: editProfileTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.chatFolders]: chatFoldersTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.editFolder]: editFolderTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.includedChats]: includedChatsTab,
|
||||
});
|
||||
|
||||
this.searchInput = new SearchInput('Telegram Search');
|
||||
@ -97,12 +113,16 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
this.backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;
|
||||
this.searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;
|
||||
|
||||
this.archivedTab = archivedTab;
|
||||
this.newChannelTab = newChannelTab;
|
||||
this.addMembersTab = addMembersTab;
|
||||
this.contactsTab = contactsTab;
|
||||
this.newGroupTab = newGroupTab;
|
||||
this.settingsTab = settingsTab;
|
||||
this.editProfileTab = editProfileTab;
|
||||
this.chatFoldersTab = chatFoldersTab;
|
||||
this.editFolderTab = editFolderTab;
|
||||
this.includedChatsTab = includedChatsTab;
|
||||
|
||||
this.menuEl = this.toolsBtn.querySelector('.btn-menu');
|
||||
this.newBtnMenu = this.sidebarEl.querySelector('#new-menu');
|
||||
@ -157,7 +177,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
});
|
||||
|
||||
this.backBtn.addEventListener('click', (e) => {
|
||||
appDialogsManager.chatsArchivedContainer.classList.remove('active');
|
||||
//appDialogsManager.chatsArchivedContainer.classList.remove('active');
|
||||
this.toolsBtn.classList.add('active');
|
||||
this.backBtn.classList.remove('active');
|
||||
this.searchContainer.classList.remove('active');
|
||||
|
@ -368,7 +368,7 @@ class AppPollResultsTab implements SliderTab {
|
||||
if(left <= 0) return;
|
||||
|
||||
const showMore = document.createElement('div');
|
||||
showMore.classList.add('poll-results-more');
|
||||
showMore.classList.add('poll-results-more', 'show-more');
|
||||
showMore.addEventListener('click', load);
|
||||
|
||||
showMore.innerHTML = `<div class="tgico-down"></div><div>Show ${Math.min(20, left)} more voter${left > 1 ? 's' : ''}</div>`;
|
||||
|
@ -41,8 +41,8 @@ export class AppUsersManager {
|
||||
public userAccess: {[userID: number]: string} = {};
|
||||
public cachedPhotoLocations: any = {};
|
||||
public contactsIndex = searchIndexManager.createIndex();
|
||||
public contactsFillPromise: Promise<number[]>;
|
||||
public contactsList: number[];
|
||||
public contactsFillPromise: Promise<Set<number>>;
|
||||
public contactsList: Set<number> = new Set();
|
||||
public myID: number;
|
||||
|
||||
constructor() {
|
||||
@ -119,20 +119,21 @@ export class AppUsersManager {
|
||||
return this.contactsFillPromise = apiManager.invokeApi('contacts.getContacts', {
|
||||
hash: 0
|
||||
}).then((result: any) => {
|
||||
let userID: number;
|
||||
this.contactsList = [];
|
||||
this.saveApiUsers(result.users);
|
||||
|
||||
result.contacts.forEach((contact: any) => {
|
||||
userID = contact.user_id;
|
||||
this.contactsList.push(userID);
|
||||
searchIndexManager.indexObject(userID, this.getUserSearchText(userID), this.contactsIndex);
|
||||
this.pushContact(contact.user_id);
|
||||
});
|
||||
|
||||
return this.contactsList;
|
||||
});
|
||||
}
|
||||
|
||||
public pushContact(userID: number) {
|
||||
this.contactsList.add(userID);
|
||||
searchIndexManager.indexObject(userID, this.getUserSearchText(userID), this.contactsIndex);
|
||||
}
|
||||
|
||||
public getUserSearchText(id: number) {
|
||||
const user = this.users[id];
|
||||
if(!user) {
|
||||
@ -148,10 +149,11 @@ export class AppUsersManager {
|
||||
}
|
||||
|
||||
public getContacts(query?: string) {
|
||||
return this.fillContacts().then(contactsList => {
|
||||
return this.fillContacts().then(_contactsList => {
|
||||
let contactsList = [..._contactsList];
|
||||
if(query) {
|
||||
const results: any = searchIndexManager.search(query, this.contactsIndex);
|
||||
const filteredContactsList = contactsList.filter(id => !!results[id]);
|
||||
const filteredContactsList = [...contactsList].filter(id => !!results[id]);
|
||||
|
||||
contactsList = filteredContactsList;
|
||||
}
|
||||
@ -300,13 +302,13 @@ export class AppUsersManager {
|
||||
return 'bot';
|
||||
}
|
||||
|
||||
let user = this.getUser(userID);
|
||||
if(!user || !user.status) {
|
||||
const user = this.getUser(userID);
|
||||
if(!user) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let str = '';
|
||||
switch(user.status._) {
|
||||
switch(user.status?._) {
|
||||
case 'userStatusRecently': {
|
||||
str = 'last seen recently';
|
||||
break;
|
||||
@ -325,19 +327,19 @@ export class AppUsersManager {
|
||||
case 'userStatusOffline': {
|
||||
str = 'last seen ';
|
||||
|
||||
let date = user.status.was_online;
|
||||
let now = Date.now() / 1000;
|
||||
const date = user.status.was_online;
|
||||
const now = Date.now() / 1000;
|
||||
|
||||
if((now - date) < 60) {
|
||||
str += ' just now';
|
||||
} else if((now - date) < 3600) {
|
||||
let c = (now - date) / 60 | 0;
|
||||
const c = (now - date) / 60 | 0;
|
||||
str += c + ' ' + (c == 1 ? 'minute' : 'minutes') + ' ago';
|
||||
} else if(now - date < 86400) {
|
||||
let c = (now - date) / 3600 | 0;
|
||||
const c = (now - date) / 3600 | 0;
|
||||
str += c + ' ' + (c == 1 ? 'hour' : 'hours') + ' ago';
|
||||
} else {
|
||||
let d = new Date(date * 1000);
|
||||
const d = new Date(date * 1000);
|
||||
str += ('0' + d.getDate()).slice(-2) + '.' + ('0' + (d.getMonth() + 1)).slice(-2) + ' at ' +
|
||||
('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2);
|
||||
}
|
||||
@ -349,6 +351,11 @@ export class AppUsersManager {
|
||||
str = 'online';
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
str = 'last seen a long time ago';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { isApple, mediaSizes, isSafari } from "./config";
|
||||
import { logger, LogLevels } from "./polyfill";
|
||||
import animationIntersector from "../components/animationIntersector";
|
||||
import apiManager from "./mtproto/mtprotoworker";
|
||||
|
||||
let convert = (value: number) => {
|
||||
return Math.round(Math.min(Math.max(value, 0), 1) * 255);
|
||||
@ -603,6 +604,19 @@ class LottieLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public loadAnimationFromURL(params: Omit<RLottieOptions, 'animationData'>, url: string) {
|
||||
if(!this.loaded) {
|
||||
this.loadLottieWorkers();
|
||||
}
|
||||
|
||||
return fetch(url)
|
||||
.then(res => res.arrayBuffer())
|
||||
.then(data => apiManager.gzipUncompress<string>(data, true))
|
||||
.then(str => {
|
||||
return this.loadAnimationWorker(Object.assign(params, {animationData: JSON.parse(str)}));
|
||||
});
|
||||
}
|
||||
|
||||
public async loadAnimationWorker(params: RLottieOptions, group = '', toneIndex = -1) {
|
||||
//params.autoplay = true;
|
||||
|
||||
@ -638,6 +652,7 @@ class LottieLoader {
|
||||
return;
|
||||
}
|
||||
|
||||
this.log.debug('onPlayerLoaded');
|
||||
rlPlayer.onLoad(frameCount, fps);
|
||||
//rlPlayer.addListener('firstFrame', () => {
|
||||
//animationIntersector.addAnimation(player, group);
|
||||
|
File diff suppressed because one or more lines are too long
@ -297,6 +297,17 @@ export function findUpTag(el, tag) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findUpAttribute(el, attribute) {
|
||||
if(el.getAttribute(attribute) != null) return el; // 03.02.2020
|
||||
|
||||
while(el.parentElement) {
|
||||
el = el.parentElement;
|
||||
if(el.getAttribute(attribute) != null)
|
||||
return el;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function whichChild(elem/* : Node */) {
|
||||
let i = 0;
|
||||
// @ts-ignore
|
||||
|
@ -236,35 +236,23 @@ let onFirstMount = (): Promise<any> => {
|
||||
|
||||
let imageDiv = page.pageEl.querySelector('.auth-image') as HTMLDivElement;
|
||||
return Promise.all([
|
||||
LottieLoader.loadLottieWorkers(),
|
||||
|
||||
fetch('assets/img/TwoFactorSetupMonkeyIdle.tgs')
|
||||
.then(res => res.arrayBuffer())
|
||||
.then(data => apiManager.gzipUncompress<string>(data, true))
|
||||
.then(str => LottieLoader.loadAnimationWorker({
|
||||
LottieLoader.loadAnimationFromURL({
|
||||
container: imageDiv,
|
||||
loop: true,
|
||||
autoplay: true,
|
||||
animationData: JSON.parse(str),
|
||||
width: 166,
|
||||
height: 166
|
||||
}))
|
||||
.then(animation => {
|
||||
}, 'assets/img/TwoFactorSetupMonkeyIdle.tgs').then(animation => {
|
||||
idleAnimation = animation;
|
||||
}),
|
||||
|
||||
/* false && */fetch('assets/img/TwoFactorSetupMonkeyTracking.tgs')
|
||||
.then(res => res.arrayBuffer())
|
||||
.then(data => apiManager.gzipUncompress<string>(data, true))
|
||||
.then(str => LottieLoader.loadAnimationWorker({
|
||||
LottieLoader.loadAnimationFromURL({
|
||||
container: imageDiv,
|
||||
loop: false,
|
||||
autoplay: false,
|
||||
animationData: JSON.parse(str),
|
||||
width: 166,
|
||||
height: 166
|
||||
}))
|
||||
.then(_animation => {
|
||||
}, 'assets/img/TwoFactorSetupMonkeyTracking.tgs').then(_animation => {
|
||||
animation = _animation;
|
||||
|
||||
if(!codeInput.value.length) {
|
||||
@ -272,7 +260,7 @@ let onFirstMount = (): Promise<any> => {
|
||||
}
|
||||
|
||||
animation.addListener('enterFrame', currentFrame => {
|
||||
console.log('enterFrame', currentFrame, needFrame);
|
||||
//console.log('enterFrame', currentFrame, needFrame);
|
||||
//let currentFrame = Math.round(e.currentTime);
|
||||
|
||||
if((animation.direction == 1 && currentFrame >= needFrame) ||
|
||||
|
@ -91,20 +91,13 @@ let onFirstMount = (): Promise<any> => {
|
||||
|
||||
}); */
|
||||
return Promise.all([
|
||||
LottieLoader.loadLottieWorkers(),
|
||||
|
||||
fetch('assets/img/TwoFactorSetupMonkeyClose.tgs')
|
||||
.then(res => res.arrayBuffer())
|
||||
.then(data => apiManager.gzipUncompress<string>(data, true))
|
||||
.then(str => LottieLoader.loadAnimationWorker({
|
||||
LottieLoader.loadAnimationFromURL({
|
||||
container: page.pageEl.querySelector('.auth-image'),
|
||||
loop: false,
|
||||
autoplay: false,
|
||||
animationData: JSON.parse(str),
|
||||
width: 166,
|
||||
height: 166
|
||||
}))
|
||||
.then(_animation => {
|
||||
}, 'assets/img/TwoFactorSetupMonkeyClose.tgs').then(_animation => {
|
||||
animation = _animation;
|
||||
animation.addListener('enterFrame', currentFrame => {
|
||||
//console.log('enterFrame', e, needFrame);
|
||||
|
@ -3,13 +3,17 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
|
||||
#bubble-contextmenu > div {
|
||||
padding: 0 84px 0 16px;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding: 0 60px 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
#topbar {
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
user-select: none;
|
||||
box-shadow: 0px 1px 5px -1px rgba(0,0,0,0.18);
|
||||
box-shadow: 0px 1px 5px -1px rgba(0,0,0,0.21);
|
||||
z-index: 1;
|
||||
min-height: 56px;
|
||||
max-height: 56px;
|
||||
@ -62,6 +66,10 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
.btn-menu {
|
||||
top: calc(100% + 7px);
|
||||
}
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-info {
|
||||
@ -73,7 +81,11 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
// padding-left: 17px;
|
||||
// line-height: 1.6;
|
||||
padding-left: 10px;
|
||||
line-height: 1.3;
|
||||
//line-height: 1.3;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
max-width: 208px;
|
||||
}
|
||||
}
|
||||
|
||||
.person {
|
||||
@ -88,7 +100,7 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
|
||||
.bottom {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
//line-height: 18px;
|
||||
color: #707579;
|
||||
|
||||
.online {
|
||||
@ -127,7 +139,7 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding: .35rem .5rem .5rem;
|
||||
padding: 0 .5rem .5rem;
|
||||
}
|
||||
|
||||
@include respond-to(not-handhelds) {
|
||||
@ -214,7 +226,7 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
height: 10px;
|
||||
background-color: #e53935;
|
||||
border-radius: 50%;
|
||||
margin: 0 .5rem;
|
||||
margin: 0 9px;
|
||||
display: inline-block;
|
||||
animation: recordBlink 1.25s infinite;
|
||||
}
|
||||
@ -231,13 +243,20 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
left: -48px;
|
||||
transition: transform .03s, visibility .1s;
|
||||
visibility: hidden;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
top: -124px;
|
||||
left: -124px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-recording {
|
||||
#btn-record-cancel {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
margin-right: .5rem;
|
||||
margin-right: 9px;
|
||||
transition: width .1s, margin-right .1s, visibility 0s .1s, opacity .1s .1s;
|
||||
}
|
||||
|
||||
@ -279,14 +298,24 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
|
||||
#im-title {
|
||||
cursor: pointer;
|
||||
margin-top: -2px;
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
span.emoji {
|
||||
vertical-align: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.info#im-subtitle {
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
display: flex;
|
||||
// padding: 200px;
|
||||
@ -471,6 +500,14 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
// height: 100%;
|
||||
height: 52px;
|
||||
padding: 1rem;
|
||||
|
||||
&-subtitle {
|
||||
line-height: 13px !important;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
max-width: 280px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,9 +567,9 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
line-height: 13px;
|
||||
}
|
||||
// @include respond-to(handhelds) {
|
||||
// line-height: 13px;
|
||||
// }
|
||||
}
|
||||
|
||||
&-subtitle {
|
||||
@ -765,6 +802,9 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
//flex-direction: unset;
|
||||
display: block;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding: 0 .5rem;
|
||||
}
|
||||
|
||||
/* display: flex;
|
||||
flex-direction: column;
|
||||
@ -814,10 +854,12 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
|
||||
&.is-chat {
|
||||
.is-in .bubble__container {
|
||||
margin-left: 3rem;
|
||||
margin-left: 45px;
|
||||
//margin-left: 3rem; #DO JS3
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
max-width: calc(100% - 3rem);
|
||||
margin-left: 45px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -899,7 +941,7 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-shadow: 0px -1px 5px -1px rgba(0,0,0,0.18);
|
||||
box-shadow: 0px -1px 5px -1px rgba(0,0,0,0.21);
|
||||
|
||||
.chat-search-count {
|
||||
margin-left: 8px;
|
||||
@ -956,7 +998,7 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
z-index: 5;
|
||||
top: 10px;
|
||||
top: 8px;
|
||||
align-items: center;
|
||||
transform: translateY(calc(-100% - 10px));
|
||||
transition: transform .2s ease;
|
||||
@ -969,7 +1011,7 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
background: rgba(0, 0, 0, .7);
|
||||
text-align: center;
|
||||
width: auto;
|
||||
padding: 12px 18px 12px 48px;
|
||||
padding: 10px 18px 12px 50px;
|
||||
min-height: 48px;
|
||||
border-radius: 12px;
|
||||
line-height: 1.5;
|
||||
@ -990,7 +1032,7 @@ $time-background: rgba(0, 0, 0, .35);
|
||||
&:before {
|
||||
content: $tgico-info2;
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
left: 15px;
|
||||
font-size: 1.5rem;
|
||||
top: 12px;
|
||||
}
|
||||
|
@ -49,6 +49,10 @@ $bubble-margin: .25rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
max-width: unquote("min(calc(100% - 46px), #{$chat-max-width})");
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
&:after {
|
||||
position: absolute;
|
||||
@ -67,6 +71,10 @@ $bubble-margin: .25rem;
|
||||
}
|
||||
|
||||
&.is-first-unread {
|
||||
@include respond-to(handhelds) {
|
||||
max-width: unset;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "Unread messages";
|
||||
height: 30px;
|
||||
@ -135,13 +143,18 @@ $bubble-margin: .25rem;
|
||||
|
||||
> .user-avatar {
|
||||
position: absolute;
|
||||
left: -3rem;
|
||||
left: -45px;
|
||||
//left: -3rem; # DO JS3
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
bottom: 0;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
|
||||
// @include respond-to(handhelds) {
|
||||
// left: -45px;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -630,6 +643,11 @@ $bubble-margin: .25rem;
|
||||
top: 0;
|
||||
margin-bottom: 0;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding: 8px 6px 8px 8px;
|
||||
max-width: 94px;
|
||||
}
|
||||
|
||||
.reply-content {
|
||||
margin-top: 0;
|
||||
}
|
||||
@ -1088,6 +1106,10 @@ $bubble-margin: .25rem;
|
||||
.reply {
|
||||
left: calc(100% + 10px);
|
||||
background-color: #fff;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
left: calc(100% + 1px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1443,7 +1465,8 @@ $bubble-margin: .25rem;
|
||||
poll-element {
|
||||
margin-top: -1px;
|
||||
display: block;
|
||||
min-width: 280px;
|
||||
//min-width: 280px;
|
||||
min-width: 330px;
|
||||
|
||||
&:not(.is-closed):not(.is-voted) .poll-answer {
|
||||
cursor: pointer;
|
||||
@ -1458,6 +1481,7 @@ poll-element {
|
||||
&-desc {
|
||||
font-size: 14px;
|
||||
color: #707579;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 7px;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
@ -1466,8 +1490,9 @@ poll-element {
|
||||
|
||||
&-hint {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
font-size: 1.5rem;
|
||||
top: -4px;
|
||||
right: 2px;
|
||||
color: #50a2e9;
|
||||
cursor: pointer;
|
||||
transform: scale(1);
|
||||
@ -1485,18 +1510,19 @@ poll-element {
|
||||
|
||||
&-avatars {
|
||||
display: flex;
|
||||
margin-left: 1rem;
|
||||
margin-left: 18px;
|
||||
}
|
||||
|
||||
&-answer {
|
||||
display: flex;
|
||||
position: relative;
|
||||
padding-bottom: 20px;
|
||||
padding-left: 34px;
|
||||
padding-left: 28px;
|
||||
margin-top: 1px;
|
||||
|
||||
&-text {
|
||||
margin-top: 7px;
|
||||
margin-left: 14px;
|
||||
margin-top: 6px;
|
||||
margin-left: 12px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@ -1507,8 +1533,9 @@ poll-element {
|
||||
opacity: 0;
|
||||
font-weight: 500;
|
||||
margin-top: 7px;
|
||||
font-size: 14px;
|
||||
transition: .34s opacity;
|
||||
margin-left: -3px;
|
||||
margin-left: -9px;
|
||||
text-align: right;
|
||||
width: 40px;
|
||||
user-select: none;
|
||||
@ -1517,7 +1544,7 @@ poll-element {
|
||||
&-selected {
|
||||
position: absolute;
|
||||
bottom: 1px;
|
||||
left: 22px;
|
||||
left: 15px;
|
||||
color: #fff;
|
||||
background: #50a2e9;
|
||||
border-radius: 50%;
|
||||
@ -1577,12 +1604,13 @@ poll-element {
|
||||
color: #707579;
|
||||
font-size: 14px;
|
||||
user-select: none;
|
||||
padding-top: 1px;
|
||||
}
|
||||
|
||||
&-line {
|
||||
height: 35px;
|
||||
position: absolute;
|
||||
left: 17.5px;
|
||||
left: 10px;
|
||||
bottom: 2px;
|
||||
transition: stroke-dashoffset .34s linear, stroke-dasharray .34s linear;
|
||||
stroke-dashoffset: 0;
|
||||
@ -1623,12 +1651,23 @@ poll-element {
|
||||
}
|
||||
|
||||
&-quiz-timer {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
stroke: #DF3F40;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
stroke: #a3adb6;
|
||||
transform: rotate(270deg);
|
||||
top: -7px;
|
||||
fill: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
right: -2px;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
|
||||
&-time {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
position: absolute;
|
||||
right: 27px;
|
||||
color: #a3adb6;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1641,7 +1680,7 @@ poll-element {
|
||||
|
||||
.poll-answer-selected {
|
||||
background: #DF3F40;
|
||||
line-height: 16px;
|
||||
//line-height: 16px;
|
||||
|
||||
&:before {
|
||||
content: $tgico-close;
|
||||
@ -1660,8 +1699,8 @@ poll-element {
|
||||
}
|
||||
|
||||
avatar-element {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 1px solid #fff;
|
||||
line-height: 20px;
|
||||
font-size: 10px;
|
||||
@ -1680,10 +1719,9 @@ poll-element {
|
||||
align-items: center;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
margin-left: 5px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
left: -1px;
|
||||
top: -1px;
|
||||
transform: scale(1);
|
||||
transition: .1s transform;
|
||||
|
||||
@ -1693,9 +1731,9 @@ poll-element {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
font-size: 16px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 20px;
|
||||
line-height: 16px;
|
||||
animation: none;
|
||||
transition: opacity .2s ease;
|
||||
@ -1727,7 +1765,7 @@ poll-element {
|
||||
stroke-dashoffset: 0;
|
||||
stroke-opacity: 1;
|
||||
stroke-width: 2;
|
||||
stroke: #8d969c;
|
||||
stroke: #dadbdc;
|
||||
fill: transparent;
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@
|
||||
|
||||
li {
|
||||
//padding: 0 0 2px 0;
|
||||
padding-bottom: 4px;
|
||||
//padding-bottom: 4px; - DO MAKETA JS3
|
||||
//overflow: hidden;
|
||||
background-color: #fff;
|
||||
|
||||
@ -106,7 +106,7 @@
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 9px 8.5px;
|
||||
margin: 0px 8px 0px 7px;
|
||||
margin: 0px 8px 0px 8px;
|
||||
overflow: hidden;
|
||||
|
||||
@media not all and (min-resolution:.001dpcm)
|
||||
@ -116,8 +116,9 @@
|
||||
}
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding: 9px 0 0 0;
|
||||
margin: 0px 11.5px 0px 9px;
|
||||
padding: 9px 12px 0 9px;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@ -189,8 +190,8 @@
|
||||
overflow: hidden;
|
||||
color: $color-gray;
|
||||
flex: 1 1 auto;
|
||||
padding: 1px 3.5px 1px 9px;
|
||||
|
||||
//padding: 1px 3.5px 1px 9px; - DO MAKETA JS3
|
||||
padding: 1px 8.5px 1px 9px; // JS3
|
||||
p:last-child {
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
@include respond-to(not-handhelds) {
|
||||
position: absolute !important;
|
||||
left: 0;
|
||||
bottom: calc(82px);
|
||||
bottom: calc(85px);
|
||||
width: 420px !important;
|
||||
height: 420px;
|
||||
box-shadow: 0px 5px 10px 5px rgba(16, 35, 47, 0.14);
|
||||
@ -30,6 +30,7 @@
|
||||
> .menu-horizontal {
|
||||
//font-weight: 500;
|
||||
margin-top: 2px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.emoji-container {
|
||||
@ -51,11 +52,13 @@
|
||||
&-search {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
margin-left: 4px !important;
|
||||
}
|
||||
|
||||
&-delete {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-right: 4px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,18 +67,21 @@
|
||||
height: 100%;
|
||||
|
||||
.category-title {
|
||||
position: sticky;
|
||||
//position: sticky;
|
||||
top: 0;
|
||||
font-size: .85rem;
|
||||
//font-size: .85rem;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: $color-gray;
|
||||
background: linear-gradient(to bottom,#fff 0,rgba(255,255,255,.9) 60%,rgba(255,255,255,0) 100%);
|
||||
//background: linear-gradient(to bottom,#fff 0,rgba(255,255,255,.9) 60%,rgba(255,255,255,0) 100%);
|
||||
z-index: 2;
|
||||
padding: .53333rem 6PX .66667rem;
|
||||
//padding: .53333rem 6PX .66667rem;
|
||||
padding: 12px 6px 6px 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.emoji-category {
|
||||
padding-top: 1px;
|
||||
//padding-top: 1px;
|
||||
position: relative;
|
||||
|
||||
.category-items {
|
||||
@ -109,7 +115,7 @@
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
padding-top: 5px;
|
||||
//padding-top: 5px;
|
||||
}
|
||||
|
||||
/* &::after {
|
||||
@ -188,35 +194,42 @@
|
||||
|
||||
.emoji-padding {
|
||||
.menu-horizontal {
|
||||
border-bottom: 1px solid $lightgrey;
|
||||
//border-bottom: 1px solid $lightgrey;
|
||||
}
|
||||
}
|
||||
|
||||
.emoji-padding, .stickers-padding {
|
||||
.menu-horizontal {
|
||||
height: 47px;
|
||||
height: 48px;
|
||||
border-bottom: none;
|
||||
padding: 2px 2px 2px 2px;
|
||||
width: 100%;
|
||||
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, 0.21);
|
||||
z-index: 4;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#content-stickers {
|
||||
.scrollable {
|
||||
padding: 15px 5px 0;
|
||||
padding: 0px 5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-horizontal {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
height: 48px;
|
||||
box-shadow: 0px -2px 5px -1px rgba(0, 0, 0, 0.21);
|
||||
|
||||
li {
|
||||
font-size: 1.65rem;
|
||||
padding: 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-size: 1.5rem;
|
||||
margin: 0 12px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
@ -224,11 +237,30 @@
|
||||
}
|
||||
|
||||
.stickers-padding {
|
||||
&.active {
|
||||
.scrollable {
|
||||
padding: 0;
|
||||
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, 0.21);
|
||||
}
|
||||
|
||||
.menu-horizontal {
|
||||
box-shadow: none;
|
||||
|
||||
& li {
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
padding: 0;
|
||||
margin-right: 1px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-wrapper {
|
||||
padding: 0;
|
||||
height: 50px;
|
||||
height: 48px;
|
||||
max-width: 100%;
|
||||
border-top: 1px solid $lightgrey;
|
||||
//border-top: 1px solid $lightgrey;
|
||||
}
|
||||
|
||||
li {
|
||||
@ -242,7 +274,8 @@
|
||||
}
|
||||
|
||||
> canvas, > img {
|
||||
padding: .75rem;
|
||||
//padding: .75rem;
|
||||
padding: 8px;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
|
@ -6,6 +6,24 @@
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.folders-tabs-scrollable {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
|
||||
.scrollable {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-horizontal {
|
||||
background: #fff;
|
||||
|
||||
ul {
|
||||
justify-content: space-between
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-slider {
|
||||
@ -46,6 +64,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-menu {
|
||||
@include respond-to(handhelds) {
|
||||
margin-top: -4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-tools-button .btn-menu {
|
||||
@ -64,6 +88,11 @@
|
||||
justify-self: flex-end;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.archived-count:empty {
|
||||
@ -219,6 +248,13 @@
|
||||
border-radius: 0.625rem;
|
||||
margin: 0px 0.5rem 0px 0.4375rem;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding: 0.75rem 0.625rem;
|
||||
height: 48px;
|
||||
margin: 0 0 2px 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
html.no-touch &:hover {
|
||||
background: rgba(112, 117, 121, 0.08);
|
||||
cursor: pointer;
|
||||
@ -240,6 +276,10 @@
|
||||
&-buttons {
|
||||
margin-top: .9375rem;
|
||||
width: 100%;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
margin-top: 0.6875rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -266,4 +306,191 @@
|
||||
.scroll-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-folders-container, .edit-folder-container {
|
||||
user-select: none;
|
||||
|
||||
.sticker-container {
|
||||
width: 86px;
|
||||
height: 86px;
|
||||
margin: 1px auto 32px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.caption {
|
||||
text-align: center;
|
||||
color: #707579;
|
||||
font-size: 14px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.sidebar-left-h2 {
|
||||
color: #707579;
|
||||
font-size: 15px;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-folders-container {
|
||||
.btn-primary {
|
||||
width: 160px;
|
||||
height: 40px;
|
||||
align-items: center;
|
||||
margin: 15px auto 24px;
|
||||
border-radius: 30px;
|
||||
padding: 0 12px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tgico-add:before {
|
||||
content: "\e903";
|
||||
font-size: 24px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.folders-container {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.category {
|
||||
padding: 7px 0 11px 0;
|
||||
display: flex;
|
||||
padding-bottom: 11px;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
p:last-child {
|
||||
color: #707579;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
height: 30px;
|
||||
font-size: 15px;
|
||||
width: 52px;
|
||||
transition: width 0.2s;
|
||||
margin: 5px 0 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.edit-folder-container {
|
||||
.caption {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
.input-wrapper {
|
||||
width: 328px;
|
||||
}
|
||||
|
||||
.input-field input {
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-left-h2 {
|
||||
padding: 21px 0 8px 16px;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.folder-list {
|
||||
li {
|
||||
padding-bottom: 2px;
|
||||
|
||||
.rp {
|
||||
padding: 8px 3px !important;
|
||||
height: 48px !important;
|
||||
}
|
||||
}
|
||||
|
||||
avatar-element {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.user-caption {
|
||||
padding: 6px 28px;
|
||||
}
|
||||
|
||||
p span {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.folder-categories {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.folder-category-button {
|
||||
display: flex;
|
||||
font-size: 1.5rem;
|
||||
padding: 13px 16px 10px 16px;
|
||||
|
||||
p {
|
||||
user-select: none;
|
||||
margin-left: 32px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&.blue, &.blue:before {
|
||||
color: #50a2e9;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:before {
|
||||
color: #797d82;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-header .tgico-check1 {
|
||||
color: #50a2e9;
|
||||
}
|
||||
|
||||
.included-chats-container {
|
||||
.sidebar-left-h2 {
|
||||
color: #707579;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
padding: 6px 0 8px 16px;
|
||||
}
|
||||
|
||||
ul {
|
||||
li > .rp {
|
||||
margin: 0 !important;
|
||||
padding: 7px 12px !important;
|
||||
height: 62px;
|
||||
}
|
||||
|
||||
.dialog-avatar {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
}
|
||||
|
||||
span.user-title {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.user-caption {
|
||||
padding: 0px 0px 0 14px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
span.user-last-message {
|
||||
font-size: 15px;
|
||||
margin-top: -1px;
|
||||
}
|
||||
}
|
||||
}
|
@ -120,6 +120,10 @@
|
||||
margin-bottom: 2px;
|
||||
margin-top: 1px;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
&.online {
|
||||
color: $color-blue;
|
||||
}
|
||||
@ -639,7 +643,7 @@
|
||||
height: 48px;
|
||||
|
||||
@include respond-to(not-handhelds) {
|
||||
padding: 8px 13px;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +134,10 @@
|
||||
margin: 0px 9px 0px 8px;
|
||||
padding: 12px 8.5px;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media not all and (min-resolution:.001dpcm)
|
||||
{ @supports (-webkit-appearance:none) {
|
||||
margin-right: 4px;
|
||||
|
@ -25,8 +25,12 @@
|
||||
&__title {
|
||||
flex: 1;
|
||||
font-weight: 500;
|
||||
padding-left: 23px;
|
||||
padding-left: 22px;
|
||||
font-size: 20px;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-icon + .btn-icon {
|
||||
|
@ -12,6 +12,7 @@
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
li {
|
||||
@ -24,6 +25,7 @@
|
||||
// font-size: 1rem;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
color: $color-blue;
|
||||
|
@ -4,10 +4,12 @@
|
||||
#{$parent} {
|
||||
&-container {
|
||||
max-height: 468px;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.input-field {
|
||||
margin-top: 25px;
|
||||
.btn-icon {
|
||||
position: absolute;
|
||||
right: .5rem;
|
||||
@ -30,4 +32,18 @@
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
.caption {
|
||||
color: #707579;
|
||||
font-weight: 500;
|
||||
padding: 16px 24px 0;
|
||||
}
|
||||
|
||||
.poll-create-questions {
|
||||
padding: 0px 20px 32.5px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-bottom: 1px solid #edeff1;
|
||||
}
|
||||
}
|
@ -53,6 +53,7 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 9px;
|
||||
padding: 12px 20px 15px;
|
||||
|
||||
.btn-primary {
|
||||
width: 79px;
|
||||
@ -125,14 +126,14 @@
|
||||
|
||||
.input-field {
|
||||
width: 100%;
|
||||
margin-top: 1rem;
|
||||
margin-top: 25px;
|
||||
|
||||
&::placeholder {
|
||||
color: #a2acb4;
|
||||
}
|
||||
|
||||
input {
|
||||
height: 54px;
|
||||
//height: 54px;
|
||||
font-size: 1rem;
|
||||
padding: 0 15px;
|
||||
border-radius: $border-radius-medium;
|
||||
@ -147,4 +148,8 @@
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-create-poll.popup-new-media .btn-primary {
|
||||
width: 94px;
|
||||
}
|
@ -347,6 +347,11 @@ input, textarea {
|
||||
&.danger:before {
|
||||
color: $color-error;
|
||||
}
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding: 0 30px 0 16px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,6 +480,7 @@ avatar-element {
|
||||
|
||||
.rp {
|
||||
position: relative;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -853,6 +859,7 @@ avatar-element {
|
||||
padding: 0 5px;
|
||||
left: .75rem;
|
||||
font-size: 0.75rem!important;
|
||||
color: #666;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@ -1386,6 +1393,26 @@ img.emoji {
|
||||
transition: opacity .2s ease;
|
||||
}
|
||||
|
||||
.show-more {
|
||||
padding-top: 13px;
|
||||
padding-bottom: 13px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
|
||||
@include respond-to(not-handhelds) {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.tgico-down {
|
||||
float: left;
|
||||
padding-right: 32px;
|
||||
padding-left: 16px;
|
||||
font-size: 24px;
|
||||
color: #707579;
|
||||
}
|
||||
}
|
||||
|
||||
/* .fade-in-end {
|
||||
opacity: 1;
|
||||
transition: opacity .2s ease;
|
||||
|
@ -5,7 +5,7 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const postcssPresetEnv = require('postcss-preset-env');
|
||||
const fs = require('fs');
|
||||
|
||||
const allowedIPs = ['195.66.140.39', '192.168.31.144', '127.0.0.1', '192.168.31.1', '192.168.31.192'];
|
||||
const allowedIPs = ['195.66.140.39', '192.168.31.144', '127.0.0.1', '192.168.31.1', '192.168.31.192', '176.100.18.181'];
|
||||
const devMode = process.env.NODE_ENV !== 'production';
|
||||
const useLocal = false;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user