Browse Source

Refactor edit profile tab

master
morethanwords 4 years ago
parent
commit
163185d021
  1. 25
      src/components/avatarEdit.ts
  2. 18
      src/components/scrollable.ts
  3. 11
      src/components/sidebarLeft/index.ts
  4. 84
      src/components/sidebarLeft/tabs/editProfile.ts
  5. 2
      src/components/sidebarLeft/tabs/settings.ts
  6. 54
      src/components/slider.ts
  7. 21
      src/index.hbs
  8. 9
      src/scss/partials/_scrollable.scss

25
src/components/avatarEdit.ts

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
import type { CancellablePromise } from "../helpers/cancellablePromise";
import type { InputFile } from "../layer";
import PopupAvatar from "./popups/avatar";
export default class AvatarEdit {
public container: HTMLElement;
private canvas: HTMLCanvasElement;
private icon: HTMLSpanElement;
constructor(onChange: (uploadAvatar: () => CancellablePromise<InputFile>) => void) {
this.container = document.createElement('div');
this.container.classList.add('avatar-edit');
this.canvas = document.createElement('canvas');
this.icon = document.createElement('span');
this.icon.classList.add('tgico', 'tgico-cameraadd');
this.container.append(this.canvas, this.icon);
this.container.addEventListener('click', () => {
new PopupAvatar().open(this.canvas, onChange);
});
}
}

18
src/components/scrollable.ts

@ -123,6 +123,7 @@ export type SliceSidesContainer = {[k in SliceSides]: boolean}; @@ -123,6 +123,7 @@ export type SliceSidesContainer = {[k in SliceSides]: boolean};
export default class Scrollable extends ScrollableBase {
public splitUp: HTMLElement;
public padding: HTMLElement;
public onAdditionalScroll: () => void = null;
public onScrolledTop: () => void = null;
@ -135,9 +136,16 @@ export default class Scrollable extends ScrollableBase { @@ -135,9 +136,16 @@ export default class Scrollable extends ScrollableBase {
public loadedAll: SliceSidesContainer = {top: true, bottom: false};
constructor(el: HTMLElement, logPrefix = '', public onScrollOffset = 300) {
constructor(el: HTMLElement, logPrefix = '', public onScrollOffset = 300, withPaddingContainer?: boolean) {
super(el, logPrefix);
if(withPaddingContainer) {
this.padding = document.createElement('div');
this.padding.classList.add('scrollable-padding');
Array.from(this.container.children).forEach(c => this.padding.append(c));
this.container.append(this.padding);
}
this.container.classList.add('scrollable-y');
this.setListeners();
}
@ -197,12 +205,12 @@ export default class Scrollable extends ScrollableBase { @@ -197,12 +205,12 @@ export default class Scrollable extends ScrollableBase {
}
};
public prepend(element: HTMLElement) {
(this.splitUp || this.container).prepend(element);
public prepend(...elements: HTMLElement[]) {
(this.splitUp || this.padding || this.container).prepend(...elements);
}
public append(element: HTMLElement) {
(this.splitUp || this.container).append(element);
public append(...elements: HTMLElement[]) {
(this.splitUp || this.padding || this.container).append(...elements);
}
public scrollIntoView(element: HTMLElement, smooth = true) {

11
src/components/sidebarLeft/index.ts

@ -34,7 +34,6 @@ const addMembersTab = new AppAddMembersTab(); @@ -34,7 +34,6 @@ const addMembersTab = new AppAddMembersTab();
const contactsTab = new AppContactsTab();
const newGroupTab = new AppNewGroupTab();
const settingsTab = new AppSettingsTab();
const editProfileTab = new AppEditProfileTab();
const editFolderTab = new AppEditFolderTab();
const includedChatsTab = new AppIncludedChatsTab();
const archivedTab = new AppArchivedTab();
@ -47,10 +46,9 @@ export class AppSidebarLeft extends SidebarSlider { @@ -47,10 +46,9 @@ export class AppSidebarLeft extends SidebarSlider {
addMembers: 4,
newGroup: 5,
settings: 6,
editProfile: 7,
chatFolders: 8,
editFolder: 9,
includedChats: 10,
chatFolders: 7,
editFolder: 8,
includedChats: 9,
};
private toolsBtn: HTMLButtonElement;
@ -102,7 +100,6 @@ export class AppSidebarLeft extends SidebarSlider { @@ -102,7 +100,6 @@ export class AppSidebarLeft extends SidebarSlider {
[AppSidebarLeft.SLIDERITEMSIDS.addMembers]: addMembersTab,
[AppSidebarLeft.SLIDERITEMSIDS.newGroup]: newGroupTab,
[AppSidebarLeft.SLIDERITEMSIDS.settings]: settingsTab,
[AppSidebarLeft.SLIDERITEMSIDS.editProfile]: editProfileTab,
[AppSidebarLeft.SLIDERITEMSIDS.chatFolders]: this.chatFoldersTab = new AppChatFoldersTab(appMessagesManager, appPeersManager, this, apiManagerProxy, rootScope),
[AppSidebarLeft.SLIDERITEMSIDS.editFolder]: editFolderTab,
[AppSidebarLeft.SLIDERITEMSIDS.includedChats]: includedChatsTab,
@ -123,9 +120,9 @@ export class AppSidebarLeft extends SidebarSlider { @@ -123,9 +120,9 @@ export class AppSidebarLeft extends SidebarSlider {
this.contactsTab = contactsTab;
this.newGroupTab = newGroupTab;
this.settingsTab = settingsTab;
this.editProfileTab = editProfileTab;
this.editFolderTab = editFolderTab;
this.includedChatsTab = includedChatsTab;
this.editProfileTab = new AppEditProfileTab(this);
this.menuEl = this.toolsBtn.querySelector('.btn-menu');
this.newBtnMenu = this.sidebarEl.querySelector('#new-menu');

84
src/components/sidebarLeft/tabs/editProfile.ts

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
import appSidebarLeft from "..";
import { InputFile } from "../../../layer";
import type { InputFile } from "../../../layer";
import appProfileManager from "../../../lib/appManagers/appProfileManager";
import appUsersManager from "../../../lib/appManagers/appUsersManager";
import apiManager from "../../../lib/mtproto/mtprotoworker";
@ -7,19 +6,17 @@ import RichTextProcessor from "../../../lib/richtextprocessor"; @@ -7,19 +6,17 @@ import RichTextProcessor from "../../../lib/richtextprocessor";
import rootScope from "../../../lib/rootScope";
import AvatarElement from "../../avatar";
import InputField from "../../inputField";
import PopupAvatar from "../../popups/avatar";
import Scrollable from "../../scrollable";
import { SliderTab } from "../../slider";
import SidebarSlider, { SliderSuperTab } from "../../slider";
import AvatarEdit from "../../avatarEdit";
import ButtonIcon from "../../buttonIcon";
// TODO: аватарка не поменяется в этой вкладке после изменения почему-то (если поставить в другом клиенте, и потом тут проверить, для этого ещё вышел в чатлист)
export default class AppEditProfileTab implements SliderTab {
private container: HTMLElement;
private scrollWrapper: HTMLElement;
export default class AppEditProfileTab extends SliderSuperTab {
//private scrollWrapper: HTMLElement;
private nextBtn: HTMLButtonElement;
private canvas: HTMLCanvasElement;
private uploadAvatar: () => Promise<InputFile> = null;
private firstNameInputField: InputField;
private lastNameInputField: InputField;
private bioInputField: InputField;
@ -28,7 +25,9 @@ export default class AppEditProfileTab implements SliderTab { @@ -28,7 +25,9 @@ export default class AppEditProfileTab implements SliderTab {
private lastNameInput: HTMLElement;
private bioInput: HTMLElement;
private userNameInput: HTMLElement;
private uploadAvatar: () => Promise<InputFile> = null;
private avatarEdit: AvatarEdit;
private avatarElem: AvatarElement;
private profileUrlContainer: HTMLDivElement;
@ -41,27 +40,28 @@ export default class AppEditProfileTab implements SliderTab { @@ -41,27 +40,28 @@ export default class AppEditProfileTab implements SliderTab {
bio: ''
};
constructor(slider: SidebarSlider) {
super(slider);
}
public init() {
this.container = document.querySelector('.edit-profile-container');
this.scrollWrapper = this.container.querySelector('.scroll-wrapper');
this.nextBtn = this.container.querySelector('.btn-corner');
this.canvas = this.container.querySelector('.avatar-edit-canvas');
this.container.classList.add('edit-profile-container');
this.title.innerText = 'Edit Profile';
//this.scrollWrapper = this.container.querySelector('.scroll-wrapper');
this.nextBtn = ButtonIcon('check btn-circle btn-corner');
this.content.append(this.nextBtn);
this.avatarElem = document.createElement('avatar-element') as AvatarElement;
this.avatarElem.classList.add('avatar-placeholder');
this.profileUrlContainer = this.container.querySelector('.profile-url-container');
this.profileUrlAnchor = this.profileUrlContainer.lastElementChild as HTMLAnchorElement;
const avatarEdit = this.container.querySelector('.avatar-edit');
avatarEdit.addEventListener('click', () => {
new PopupAvatar().open(this.canvas, (_upload) => {
this.uploadAvatar = _upload;
this.handleChange();
this.avatarElem.remove();
});
this.avatarEdit = new AvatarEdit((_upload) => {
this.uploadAvatar = _upload;
this.handleChange();
this.avatarElem.remove();
});
this.scrollable.append(this.avatarEdit.container);
{
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
@ -87,10 +87,21 @@ export default class AppEditProfileTab implements SliderTab { @@ -87,10 +87,21 @@ export default class AppEditProfileTab implements SliderTab {
this.bioInput = this.bioInputField.input;
inputWrapper.append(this.firstNameInputField.container, this.lastNameInputField.container, this.bioInputField.container);
avatarEdit.parentElement.insertBefore(inputWrapper, avatarEdit.nextElementSibling);
const caption = document.createElement('div');
caption.classList.add('caption');
caption.innerHTML = 'Any details such as age, occupation or city. Example:<br>23 y.o. designer from San Francisco.';
this.scrollable.append(inputWrapper, caption);
}
this.scrollable.append(document.createElement('hr'));
{
const h2 = document.createElement('div');
h2.classList.add('sidebar-left-h2');
h2.innerText = 'Username';
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
@ -102,9 +113,16 @@ export default class AppEditProfileTab implements SliderTab { @@ -102,9 +113,16 @@ export default class AppEditProfileTab implements SliderTab {
this.userNameInput = this.userNameInputField.input;
inputWrapper.append(this.userNameInputField.container);
const caption = this.profileUrlContainer.parentElement;
caption.parentElement.insertBefore(inputWrapper, caption);
const caption = document.createElement('div');
caption.classList.add('caption');
caption.innerHTML = `You can choose a username on Telegram. If you do, other people will be able to find you by this username and contact you without knowing your phone number.<br><br>You can use a-z, 0-9 and underscores. Minimum length is 5 characters.<br><br><div class="profile-url-container">This link opens a chat with you:
<br><a class="profile-url" href="#" target="_blank"></a></div>`;
this.profileUrlContainer = caption.querySelector('.profile-url-container');
this.profileUrlAnchor = this.profileUrlContainer.lastElementChild as HTMLAnchorElement;
this.scrollable.append(h2, inputWrapper, caption);
}
let userNameLabel = this.userNameInput.nextElementSibling as HTMLLabelElement;
@ -173,7 +191,7 @@ export default class AppEditProfileTab implements SliderTab { @@ -173,7 +191,7 @@ export default class AppEditProfileTab implements SliderTab {
let promises: Promise<any>[] = [];
promises.push(appProfileManager.updateProfile(this.firstNameInputField.value, this.lastNameInputField.value, this.bioInputField.value).then(() => {
appSidebarLeft.selectTab(0);
this.slider.selectTab(0);
}, (err) => {
console.error('updateProfile error:', err);
}));
@ -192,8 +210,6 @@ export default class AppEditProfileTab implements SliderTab { @@ -192,8 +210,6 @@ export default class AppEditProfileTab implements SliderTab {
this.nextBtn.removeAttribute('disabled');
});
});
let scrollable = new Scrollable(this.scrollWrapper as HTMLElement);
}
public fillElements() {
@ -230,7 +246,7 @@ export default class AppEditProfileTab implements SliderTab { @@ -230,7 +246,7 @@ export default class AppEditProfileTab implements SliderTab {
this.avatarElem.setAttribute('peer', '' + rootScope.myId);
if(!this.avatarElem.parentElement) {
this.canvas.parentElement.append(this.avatarElem);
this.avatarEdit.container.append(this.avatarElem);
}
this.uploadAvatar = null;

2
src/components/sidebarLeft/tabs/settings.ts

@ -37,7 +37,7 @@ export default class AppSettingsTab implements SliderTab { @@ -37,7 +37,7 @@ export default class AppSettingsTab implements SliderTab {
this.buttons.edit.addEventListener('click', () => {
appSidebarLeft.editProfileTab.fillElements();
appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.editProfile);
appSidebarLeft.editProfileTab.open();
});
this.buttons.folders.addEventListener('click', () => {

54
src/components/slider.ts

@ -1,5 +1,8 @@ @@ -1,5 +1,8 @@
import { attachClickEvent } from "../helpers/dom";
import { horizontalMenu } from "./horizontalMenu";
import ButtonIcon from "./buttonIcon";
import Scrollable from "./scrollable";
import { p } from "../mock/srp";
export interface SliderTab {
onOpen?: () => void,
@ -8,15 +11,42 @@ export interface SliderTab { @@ -8,15 +11,42 @@ export interface SliderTab {
onCloseAfterTimeout?: () => void
}
export class SuperSliderTab implements SliderTab {
public id: number;
export class SliderSuperTab implements SliderTab {
public container: HTMLElement;
public header: HTMLElement;
public closeBtn: HTMLElement;
public title: HTMLElement;
public content: HTMLElement;
public scrollable: Scrollable;
public id: number;
// fix incompability
public onOpen: SliderTab['onOpen'];
constructor(protected slider: SidebarSlider, public container: HTMLElement) {
this.closeBtn = this.container.querySelector('.sidebar-close-button');
constructor(protected slider: SidebarSlider) {
this.container = document.createElement('div');
this.container.classList.add('sidebar-slider-item');
// * Header
this.header = document.createElement('div');
this.header.classList.add('sidebar-header');
this.closeBtn = ButtonIcon('back sidebar-close-button', {noRipple: true});
this.title = document.createElement('div');
this.title.classList.add('sidebar-header__title');
this.header.append(this.closeBtn, this.title);
// * Content
this.content = document.createElement('div');
this.content.classList.add('sidebar-content');
this.scrollable = new Scrollable(this.content, undefined, undefined, true);
this.container.append(this.header, this.content);
this.id = this.slider.addTab(this);
}
@ -34,9 +64,11 @@ const TRANSITION_TIME = 250; @@ -34,9 +64,11 @@ const TRANSITION_TIME = 250;
export default class SidebarSlider {
protected _selectTab: (id: number) => void;
public historyTabIds: number[] = [];
public tabsContainer: HTMLElement;
constructor(public sidebarEl: HTMLElement, public tabs: {[id: number]: SliderTab} = {}, private canHideFirst = false) {
this._selectTab = horizontalMenu(null, this.sidebarEl.querySelector('.sidebar-slider') as HTMLDivElement, null, null, TRANSITION_TIME);
this.tabsContainer = this.sidebarEl.querySelector('.sidebar-slider');
this._selectTab = horizontalMenu(null, this.tabsContainer as HTMLDivElement, null, null, TRANSITION_TIME);
if(!canHideFirst) {
this._selectTab(0);
}
@ -58,8 +90,8 @@ export default class SidebarSlider { @@ -58,8 +90,8 @@ export default class SidebarSlider {
return true;
};
public selectTab(id: number | SuperSliderTab): boolean {
if(id instanceof SuperSliderTab) {
public selectTab(id: number | SliderSuperTab): boolean {
if(id instanceof SliderSuperTab) {
id = id.id;
}
@ -105,13 +137,13 @@ export default class SidebarSlider { @@ -105,13 +137,13 @@ export default class SidebarSlider {
}
}
public addTab(tab: SuperSliderTab) {
public addTab(tab: SliderSuperTab) {
let id: number;
if(tab.container.parentElement) {
id = Array.from(this.sidebarEl.children).findIndex(el => el === tab.container);
id = Array.from(this.tabsContainer.children).findIndex(el => el === tab.container);
} else {
id = this.sidebarEl.childElementCount;
this.sidebarEl.append(tab.container);
id = this.tabsContainer.childElementCount;
this.tabsContainer.append(tab.container);
if(tab.closeBtn) {
tab.closeBtn.addEventListener('click', () => this.closeTab());

21
src/index.hbs

@ -246,27 +246,6 @@ @@ -246,27 +246,6 @@
</div>
</div>
</div>
<div class="sidebar-slider-item edit-profile-container">
<div class="sidebar-header">
<button class="btn-icon tgico-back sidebar-close-button"></button>
<div class="sidebar-header__title">Edit Profile</div>
</div>
<div class="sidebar-content">
<div class="scroll-wrapper">
<div class="avatar-edit">
<canvas class="avatar-edit-canvas"></canvas>
<span class="tgico tgico-cameraadd"></span>
</div>
<div class="caption">Any details such as age, occupation or city. Example:<br>23 y.o. designer from San Francisco.</div>
<hr/>
<div class="sidebar-left-h2">Username</div>
<div class="caption">You can choose a username on Telegram. If you do, other people will be able to find you by this username and contact you without knowing your phone number.<br><br>You can use a-z, 0-9 and underscores. Minimum length is 5 characters.<br><br><div class="profile-url-container">This link opens a chat with you:
<br><a class="profile-url" href="#" target="_blank"></a></div>
</div>
</div>
<button class="btn-circle rp btn-corner tgico-check"></button>
</div>
</div>
<div class="sidebar-slider-item chat-folders-container">
<div class="sidebar-header">
<button class="btn-icon tgico-back sidebar-close-button"></button>

9
src/scss/partials/_scrollable.scss

@ -58,6 +58,15 @@ @@ -58,6 +58,15 @@
}
}
&-padding {
min-width: 100%;
height: 100%;
}
html.is-safari &-padding {
margin-right: -6px;
}
/* &-sentinel {
position: relative;
left: 0;

Loading…
Cancel
Save