commit
5cd55393f8
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "sengi",
|
||||
"version": "0.12.2",
|
||||
"version": "0.14.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "sengi",
|
||||
"version": "0.14.0",
|
||||
"version": "0.15.0",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "main-electron.js",
|
||||
"description": "A multi-account desktop client for Mastodon and Pleroma",
|
||||
|
@ -129,7 +129,9 @@
|
|||
"category": "Network"
|
||||
},
|
||||
"snap": {
|
||||
"publish": ["github"]
|
||||
"publish": [
|
||||
"github"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
(suggestionSelectedEvent)="suggestionSelected($event)" (hasSuggestionsEvent)="suggestionsChanged($event)">
|
||||
</app-autosuggest>
|
||||
|
||||
<div class="status-editor__footer">
|
||||
<div class="status-editor__footer" #footer>
|
||||
<button type="submit" title="reply" class="status-editor__footer--send-button" *ngIf="statusReplyingToWrapper">
|
||||
<span *ngIf="!isSending">REPLY!</span>
|
||||
<app-waiting-animation class="waiting-icon" *ngIf="isSending"></app-waiting-animation>
|
||||
|
|
|
@ -30,6 +30,7 @@ $counter-width: 90px;
|
|||
.status-editor {
|
||||
position: relative;
|
||||
font-size: $default-font-size;
|
||||
margin-bottom: 5px;
|
||||
|
||||
&__title {
|
||||
background-color: $status-editor-title-background;
|
||||
|
|
|
@ -111,6 +111,7 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
|
|||
@Output() onClose = new EventEmitter();
|
||||
@ViewChild('reply') replyElement: ElementRef;
|
||||
@ViewChild('fileInput') fileInputElement: ElementRef;
|
||||
@ViewChild('footer') footerElement: ElementRef;
|
||||
@ViewChild(ContextMenuComponent) public contextMenu: ContextMenuComponent;
|
||||
|
||||
private _isDirectMention: boolean;
|
||||
|
@ -223,7 +224,7 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
private getWordByPos(str, pos) {
|
||||
str = str.replace(/(\r\n|\n|\r)/gm,"");
|
||||
str = str.replace(/(\r\n|\n|\r)/gm, "");
|
||||
var left = str.substr(0, pos);
|
||||
var right = str.substr(pos);
|
||||
|
||||
|
@ -512,7 +513,7 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
|
|||
let mentionExtraChars = 0;
|
||||
let links = status.split(' ').filter(x => x.startsWith('http://') || x.startsWith('https://'));
|
||||
for (let link of links) {
|
||||
if(link.length > 23){
|
||||
if (link.length > 23) {
|
||||
mentionExtraChars += link.length - 23;
|
||||
}
|
||||
}
|
||||
|
@ -610,11 +611,24 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
|
|||
let scrolling = (this.replyElement.nativeElement.scrollHeight);
|
||||
|
||||
if (scrolling > 110) {
|
||||
this.replyElement.nativeElement.style.height = `0px`;
|
||||
const isVisible = this.checkVisible(this.footerElement.nativeElement);
|
||||
//this.replyElement.nativeElement.style.height = `0px`;
|
||||
this.replyElement.nativeElement.style.height = `${this.replyElement.nativeElement.scrollHeight}px`;
|
||||
|
||||
if (isVisible) {
|
||||
setTimeout(() => {
|
||||
this.footerElement.nativeElement.scrollIntoViewIfNeeded({ behavior: 'instant', block: 'end', inline: 'start' });
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private checkVisible(elm) {
|
||||
var rect = elm.getBoundingClientRect();
|
||||
var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
|
||||
return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
|
||||
}
|
||||
|
||||
public onContextMenu($event: MouseEvent): void {
|
||||
this.contextMenuService.show.next({
|
||||
// Optional - if unspecified, all context menu components will open
|
||||
|
|
|
@ -1,28 +1,30 @@
|
|||
<div class="floating-column">
|
||||
<app-stream-overlay class="stream-overlay" *ngIf="overlayActive" (closeOverlay)="closeOverlay()"
|
||||
[browseAccountData]="overlayAccountToBrowse"
|
||||
[browseHashtagData]="overlayHashtagToBrowse"
|
||||
[browseThreadData]="overlayThreadToBrowse"></app-stream-overlay>
|
||||
<div class="floating-column__inner">
|
||||
<div class="sliding-column" [class.sliding-column__right-display]="overlayActive">
|
||||
<app-stream-overlay class="stream-overlay" *ngIf="overlayActive"
|
||||
(closeOverlay)="closeOverlay()"
|
||||
[browseAccountData]="overlayAccountToBrowse"
|
||||
[browseHashtagData]="overlayHashtagToBrowse"
|
||||
[browseThreadData]="overlayThreadToBrowse"></app-stream-overlay>
|
||||
|
||||
<div class="floating-column__header">
|
||||
<a class="close-button" href (click)="closePanel()" title="close">
|
||||
<fa-icon [icon]="faTimes"></fa-icon>
|
||||
</a>
|
||||
<div class="floating-column__inner--left">
|
||||
<div class="floating-column__header">
|
||||
<a class="close-button" href (click)="closePanel()" title="close">
|
||||
<fa-icon [icon]="faTimes"></fa-icon>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<app-manage-account *ngIf="openPanel === 'manageAccount'" [account]="userAccountUsed"
|
||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-manage-account>
|
||||
<app-add-new-status *ngIf="openPanel === 'createNewStatus'" [isDirectMention]="isDirectMention"
|
||||
[userHandle]="userHandle" [redraftedStatus]="redraftedStatus"></app-add-new-status>
|
||||
<app-add-new-account *ngIf="openPanel === 'addNewAccount'"></app-add-new-account>
|
||||
<app-search *ngIf="openPanel === 'search'" (browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)">
|
||||
</app-search>
|
||||
<app-settings *ngIf="openPanel === 'settings'"></app-settings>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-manage-account *ngIf="openPanel === 'manageAccount'"
|
||||
[account]="userAccountUsed"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-manage-account>
|
||||
<app-add-new-status *ngIf="openPanel === 'createNewStatus'"
|
||||
[isDirectMention]="isDirectMention"
|
||||
[userHandle]="userHandle"
|
||||
[redraftedStatus]="redraftedStatus"></app-add-new-status>
|
||||
<app-add-new-account *ngIf="openPanel === 'addNewAccount'"></app-add-new-account>
|
||||
<app-search *ngIf="openPanel === 'search'"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-search>
|
||||
<app-settings *ngIf="openPanel === 'settings'"></app-settings>
|
||||
</div>
|
|
@ -1,11 +1,8 @@
|
|||
@import "variables";
|
||||
@import "mixins";
|
||||
@import "panel";
|
||||
|
||||
|
||||
.floating-column {
|
||||
width: calc(100%);
|
||||
width: $floating-column-size;
|
||||
|
||||
.floating-column {
|
||||
background-color: $color-secondary;
|
||||
overflow: hidden;
|
||||
z-index: 200;
|
||||
|
@ -16,16 +13,19 @@
|
|||
|
||||
white-space: normal;
|
||||
|
||||
// &__header {
|
||||
|
||||
// }
|
||||
}
|
||||
&__inner {
|
||||
position: relative;
|
||||
width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
|
||||
.stream-overlay {
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
width: $floating-column-size;
|
||||
height: calc(100%);
|
||||
margin: 0 0 0 $stream-column-separator;
|
||||
overflow: hidden;
|
||||
|
||||
&--left {
|
||||
width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
|
@ -34,27 +34,4 @@
|
|||
font-size: 14px;
|
||||
color: white;
|
||||
margin: 10px 16px 0 0;
|
||||
|
||||
// display: inline-block;
|
||||
// background-color: $color-primary;
|
||||
// color: darken(white, 30);
|
||||
// border-radius: 999px;
|
||||
// width: 26px;
|
||||
// height: 26px;
|
||||
// text-align: center;
|
||||
// text-decoration: none;
|
||||
// padding: 1px;
|
||||
|
||||
// z-index: 9999;
|
||||
// float: right;
|
||||
// margin: 10px;
|
||||
|
||||
// transition: all .2s;
|
||||
|
||||
// &:hover {
|
||||
// background-color: lighten($color-primary, 20);
|
||||
// color: white;
|
||||
// // transform: scale(1.2);
|
||||
// }
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { Component, OnInit, Output, EventEmitter, Input, ViewChild } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Component, OnInit, Output, EventEmitter, Input, ViewChild, OnDestroy } from '@angular/core';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
import { Store } from '@ngxs/store';
|
||||
|
||||
import { StreamElement, StreamTypeEnum, AddStream } from '../../../states/streams.state';
|
||||
|
@ -12,8 +12,10 @@ import { AccountInfo } from '../../../states/accounts.state';
|
|||
templateUrl: './hashtag.component.html',
|
||||
styleUrls: ['./hashtag.component.scss']
|
||||
})
|
||||
export class HashtagComponent implements OnInit {
|
||||
|
||||
export class HashtagComponent implements OnInit, OnDestroy {
|
||||
@Input() refreshEventEmitter: EventEmitter<any>;
|
||||
@Input() goToTopEventEmitter: EventEmitter<any>;
|
||||
|
||||
@Output() browseAccountEvent = new EventEmitter<string>();
|
||||
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
|
||||
|
@ -27,18 +29,37 @@ export class HashtagComponent implements OnInit {
|
|||
get hashtagElement(): StreamElement{
|
||||
return this._hashtagElement;
|
||||
}
|
||||
|
||||
|
||||
@ViewChild('appStreamStatuses') appStreamStatuses: StreamStatusesComponent;
|
||||
|
||||
goToTopSubject: Subject<void> = new Subject<void>();
|
||||
|
||||
private lastUsedAccount: AccountInfo;
|
||||
private refreshSubscription: Subscription;
|
||||
private goToTopSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private readonly store: Store,
|
||||
private readonly toolsService: ToolsService) { }
|
||||
|
||||
ngOnInit() {
|
||||
if(this.refreshEventEmitter) {
|
||||
this.refreshSubscription = this.refreshEventEmitter.subscribe(() => {
|
||||
this.refresh();
|
||||
})
|
||||
}
|
||||
|
||||
if(this.goToTopEventEmitter) {
|
||||
this.goToTopSubscription = this.goToTopEventEmitter.subscribe(() => {
|
||||
this.goToTop();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if(this.refreshSubscription) this.refreshSubscription.unsubscribe();
|
||||
if (this.goToTopSubscription) this.goToTopSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
goToTop(): boolean {
|
||||
|
@ -66,6 +87,8 @@ export class HashtagComponent implements OnInit {
|
|||
}
|
||||
|
||||
browseHashtag(hashtag: string) {
|
||||
if(this.hashtagElement.tag === hashtag) return false;
|
||||
|
||||
this.browseHashtagEvent.next(hashtag);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,20 +49,19 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy {
|
|||
|
||||
ngOnInit() {
|
||||
if (this.statusWrapper) {
|
||||
|
||||
const status = this.statusWrapper.status;
|
||||
if (status.reblog) {
|
||||
this.displayedStatus = status.reblog;
|
||||
} else {
|
||||
this.displayedStatus = status;
|
||||
}
|
||||
|
||||
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
|
||||
this.loadedAccounts = accounts;
|
||||
this.checkStatus(accounts);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
|
||||
this.loadedAccounts = accounts;
|
||||
if (this.statusWrapper) this.checkStatus(accounts);
|
||||
});
|
||||
|
||||
let account: Account;
|
||||
if(this.statusWrapper) {
|
||||
account = this.displayedStatus.account;
|
||||
|
|
|
@ -1 +1 @@
|
|||
<div #content class="content" [class.selectable]="textIsSelectable" innerHTML="{{processedText}}" (click)="selectText()"></div>
|
||||
<div #content class="content" [class.selectable]="textIsSelectable" innerHTML="{{processedText}}" (click)="selectText($event)"></div>
|
|
@ -238,8 +238,10 @@ export class DatabindedTextComponent implements OnInit {
|
|||
this.hashtagSelected.next(hashtag);
|
||||
}
|
||||
|
||||
selectText() {
|
||||
this.textSelected.next();
|
||||
selectText(event) {
|
||||
if (event.view.getSelection().toString().length === 0) {
|
||||
this.textSelected.next();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="status-wrapper" [class.direct-message]="isDirectMessage">
|
||||
<div class="status-wrapper" [class.direct-message]="isDirectMessage" [class.status-selected]="isSelected">
|
||||
<div class="reblog" *ngIf="reblog">
|
||||
<a class="reblog__profile-link" href title="{{ status.account.acct }}"
|
||||
(click)="openAccount(status.account)"
|
||||
|
|
|
@ -33,6 +33,13 @@
|
|||
background-color: $direct-message-background;
|
||||
}
|
||||
|
||||
.status-selected {
|
||||
background-color: #0f111a;
|
||||
background-color: desaturate(lighten(#0f111a, 5%), 4%);
|
||||
background-color: #0a0a10;
|
||||
background-color: #1e2734;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter, ViewChild } from "@angular/core";
|
||||
import { Component, OnInit, Input, Output, EventEmitter, ViewChild, ElementRef } from "@angular/core";
|
||||
import { faStar, faRetweet, faList, faThumbtack } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import { Status, Account } from "../../../services/models/mastodon.interfaces";
|
||||
|
@ -36,6 +36,7 @@ export class StatusComponent implements OnInit {
|
|||
hasReply: boolean;
|
||||
contentWarningText: string;
|
||||
isDirectMessage: boolean;
|
||||
isSelected: boolean;
|
||||
|
||||
@Output() browseAccountEvent = new EventEmitter<string>();
|
||||
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||
|
@ -49,6 +50,7 @@ export class StatusComponent implements OnInit {
|
|||
|
||||
private _statusWrapper: StatusWrapper;
|
||||
status: Status;
|
||||
|
||||
@Input('statusWrapper')
|
||||
set statusWrapper(value: StatusWrapper) {
|
||||
this._statusWrapper = value;
|
||||
|
@ -85,6 +87,7 @@ export class StatusComponent implements OnInit {
|
|||
}
|
||||
|
||||
constructor(
|
||||
public elem: ElementRef,
|
||||
private readonly toolsService: ToolsService) { }
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -163,6 +166,8 @@ export class StatusComponent implements OnInit {
|
|||
}
|
||||
|
||||
textSelected(): boolean {
|
||||
if(this.isSelected) return false;
|
||||
|
||||
const status = this._statusWrapper.status;
|
||||
const accountInfo = this._statusWrapper.provider;
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
@import "mixins";
|
||||
|
||||
.stream-edition {
|
||||
width: 100%;
|
||||
width: calc(100%);
|
||||
width: $stream-column-width;
|
||||
// min-height: 50px;
|
||||
background-color: #222736;
|
||||
border-bottom: 1px solid $color-secondary;
|
||||
|
|
|
@ -4,29 +4,49 @@
|
|||
<fa-icon [icon]="faTimes"></fa-icon>
|
||||
</button>
|
||||
|
||||
<button class="overlay__button overlay-previous" [ngClass]="{'overlay__button--focus': previousElements.length > 0 }" title="previous" (click)="previous()">
|
||||
<button class="overlay__button overlay-previous"
|
||||
[ngClass]="{'overlay__button--focus': hasPreviousElements }" title="previous" (click)="previous()">
|
||||
<fa-icon [icon]="faAngleLeft"></fa-icon>
|
||||
</button>
|
||||
<button class="overlay__button overlay-refresh" [ngClass]="{'overlay__button--focus': refreshFocused }" title="refresh" (click)="refresh()">
|
||||
<button class="overlay__button overlay-refresh" [ngClass]="{'overlay__button--focus': refreshFocused }"
|
||||
title="refresh" (click)="refresh()">
|
||||
<fa-icon [icon]="faRedoAlt"></fa-icon>
|
||||
</button>
|
||||
<button class="overlay__button overlay-next" [ngClass]="{'overlay__button--focus': nextElements.length > 0 }" title="next" (click)="next()">
|
||||
<fa-icon [icon]="faAngleRight"></fa-icon>
|
||||
</button>
|
||||
|
||||
<!-- <a href class="overlay-close" (click)="close()">CLOSE</a>
|
||||
<a href class="overlay-previous" (click)="previous()">PREV</a>
|
||||
<a href class="overlay-refresh" *ngIf="canRefresh" (click)="refresh()">REFRESH</a>
|
||||
<a href class="overlay-next" *ngIf="canGoForward" (click)="next()">NEXT</a> -->
|
||||
<a href title="return to top" class="overlay-gototop" (click)="goToTop()">
|
||||
|
||||
</a>
|
||||
|
||||
<button class="overlay__button overlay-next" [ngClass]="{'overlay__button--focus': hasNextElements }"
|
||||
title="next" (click)="next()">
|
||||
<fa-icon [icon]="faAngleRight"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<app-user-profile #appUserProfile *ngIf="accountName" [currentAccount]="accountName" class="stream-overlay__content"
|
||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-user-profile>
|
||||
<app-hashtag #appHashtag *ngIf="hashtagElement" [hashtagElement]="hashtagElement" class="stream-overlay__content"
|
||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-hashtag>
|
||||
<app-thread #appThread *ngIf="browseThread" [currentThread]="thread" class="stream-overlay__content"
|
||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-thread>
|
||||
<div *ngFor="let e of loadedElements" class="stream-overlay__content-wrapper"
|
||||
[class.stream-overlay__content-wrapper--selected]="e.isVisible">
|
||||
<app-user-profile #appUserProfile *ngIf="e.type === 'account'"
|
||||
[currentAccount]="e.account"
|
||||
[refreshEventEmitter]="e.refreshEventEmitter"
|
||||
[goToTopEventEmitter]="e.goToTopEventEmitter"
|
||||
class="stream-overlay__content"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-user-profile>
|
||||
<app-hashtag #appHashtag *ngIf="e.type === 'hashtag'"
|
||||
[hashtagElement]="e.hashtag"
|
||||
[refreshEventEmitter]="e.refreshEventEmitter"
|
||||
[goToTopEventEmitter]="e.goToTopEventEmitter"
|
||||
class="stream-overlay__content"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-hashtag>
|
||||
<app-thread #appThread *ngIf="e.type === 'thread'"
|
||||
[currentThread]="e.thread" class="stream-overlay__content"
|
||||
[refreshEventEmitter]="e.refreshEventEmitter"
|
||||
[goToTopEventEmitter]="e.goToTopEventEmitter"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-thread>
|
||||
</div>
|
||||
</div>
|
|
@ -1,14 +1,16 @@
|
|||
@import "variables";
|
||||
@import "mixins";
|
||||
@import "commons";
|
||||
$header-content: 40px;
|
||||
$header-content-height: 40px;
|
||||
.stream-overlay {
|
||||
// width: $stream-column-width;
|
||||
// width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
background-color: $column-color;
|
||||
position: relative;
|
||||
|
||||
&__header {
|
||||
width: calc(100%);
|
||||
height: $header-content;
|
||||
height: $header-content-height;
|
||||
background-color: $column-header-background-color; // padding: 6px 10px 0 10px;
|
||||
border-bottom: 1px solid #222736;
|
||||
& a {
|
||||
|
@ -17,10 +19,29 @@ $header-content: 40px;
|
|||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
&__content-wrapper {
|
||||
transition: all .2s;
|
||||
position: absolute;
|
||||
top: $header-content-height;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
|
||||
// outline: 1px solid greenyellow;
|
||||
// background-color: salmon;
|
||||
|
||||
z-index: 1;
|
||||
opacity: 0;
|
||||
|
||||
&--selected {
|
||||
z-index: 10;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
&__content {
|
||||
display: block;
|
||||
width: calc(100%);
|
||||
height: calc(100% - #{$header-content});
|
||||
height: calc(100%);
|
||||
}
|
||||
&__title {
|
||||
width: calc(100%);
|
||||
|
@ -42,10 +63,15 @@ $header-content: 40px;
|
|||
transition: all .2s;
|
||||
margin: 8px 0 0 8px;
|
||||
&:hover {
|
||||
color: whitesmoke;
|
||||
color: #536599;
|
||||
color: #7a8dc7;
|
||||
}
|
||||
&--focus {
|
||||
color: whitesmoke;
|
||||
|
||||
&:hover {
|
||||
color: whitesmoke;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-previous {
|
||||
|
@ -67,13 +93,21 @@ $header-content: 40px;
|
|||
float: left;
|
||||
font-size: 18px;
|
||||
}
|
||||
&-gototop {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 110px;
|
||||
right: 40px;
|
||||
display: block;
|
||||
height: $header-content-height;
|
||||
}
|
||||
&-close {
|
||||
display: block;
|
||||
float: right;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.not-active {
|
||||
|
|
|
@ -5,9 +5,6 @@ import { Store } from '@ngxs/store';
|
|||
|
||||
import { ToolsService, OpenThreadEvent } from '../../../services/tools.service';
|
||||
import { StreamElement, StreamTypeEnum } from '../../../states/streams.state';
|
||||
import { ThreadComponent } from '../thread/thread.component';
|
||||
import { UserProfileComponent } from '../user-profile/user-profile.component';
|
||||
import { HashtagComponent } from '../hashtag/hashtag.component';
|
||||
import { AccountInfo } from '../../../states/accounts.state';
|
||||
|
||||
|
||||
|
@ -21,18 +18,13 @@ export class StreamOverlayComponent implements OnInit, OnDestroy {
|
|||
faAngleRight = faAngleRight;
|
||||
faTimes = faTimes;
|
||||
faRedoAlt = faRedoAlt;
|
||||
|
||||
|
||||
refreshFocused: boolean;
|
||||
previousElements: OverlayBrowsing[] = [];
|
||||
nextElements: OverlayBrowsing[] = [];
|
||||
private currentElement: OverlayBrowsing;
|
||||
hasPreviousElements: boolean;
|
||||
hasNextElements: boolean;
|
||||
|
||||
// canRefresh: boolean = true;
|
||||
// canGoForward: boolean;
|
||||
|
||||
accountName: string;
|
||||
thread: OpenThreadEvent;
|
||||
hashtagElement: StreamElement;
|
||||
loadedElements: OverlayBrowsing[] = [];
|
||||
visibleElementIndex: number = -1;
|
||||
|
||||
@Output() closeOverlay = new EventEmitter();
|
||||
|
||||
|
@ -51,17 +43,13 @@ export class StreamOverlayComponent implements OnInit, OnDestroy {
|
|||
this.browseHashtag(hashtag);
|
||||
}
|
||||
|
||||
@ViewChild('appUserProfile') appUserProfile: UserProfileComponent;
|
||||
@ViewChild('appHashtag') appHashtag: HashtagComponent;
|
||||
@ViewChild('appThread') appThread: ThreadComponent;
|
||||
|
||||
private currentlyUsedAccount: AccountInfo;
|
||||
private accounts$: Observable<AccountInfo[]>;
|
||||
private accountSub: Subscription;
|
||||
|
||||
constructor(
|
||||
private readonly store: Store,
|
||||
private readonly toolsService: ToolsService) {
|
||||
private readonly toolsService: ToolsService) {
|
||||
this.accounts$ = this.store.select(state => state.registeredaccounts.accounts);
|
||||
}
|
||||
|
||||
|
@ -87,36 +75,41 @@ export class StreamOverlayComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
next(): boolean {
|
||||
if (this.nextElements.length === 0) {
|
||||
if (this.visibleElementIndex >= this.loadedElements.length - 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.currentElement) {
|
||||
this.previousElements.push(this.currentElement);
|
||||
}
|
||||
this.loadedElements[this.visibleElementIndex].hide();
|
||||
let newIndex = this.visibleElementIndex + 1;
|
||||
this.loadedElements[newIndex].show();
|
||||
this.visibleElementIndex = newIndex;
|
||||
|
||||
const nextElement = this.nextElements.pop();
|
||||
this.loadElement(nextElement);
|
||||
console.warn(`visibleElementIndex ${this.visibleElementIndex}`);
|
||||
console.warn(`this.loadedElements ${this.loadedElements.length}`);
|
||||
|
||||
//if(this.nextElements.length === 0) this.canGoForward = false;
|
||||
this.hasPreviousElements = true;
|
||||
this.hasNextElements = this.visibleElementIndex < this.loadedElements.length - 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
previous(): boolean {
|
||||
if (this.previousElements.length === 0) {
|
||||
if (this.visibleElementIndex <= 0) {
|
||||
this.closeOverlay.next();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.currentElement) {
|
||||
this.nextElements.push(this.currentElement);
|
||||
}
|
||||
this.loadedElements[this.visibleElementIndex].hide();
|
||||
let newIndex = this.visibleElementIndex - 1;
|
||||
this.loadedElements[newIndex].show();
|
||||
this.visibleElementIndex = newIndex;
|
||||
|
||||
const previousElement = this.previousElements.pop();
|
||||
this.loadElement(previousElement);
|
||||
console.warn(`visibleElementIndex ${this.visibleElementIndex}`);
|
||||
console.warn(`this.loadedElements ${this.loadedElements.length}`);
|
||||
|
||||
this.hasPreviousElements = this.visibleElementIndex > 0;
|
||||
this.hasNextElements = true;
|
||||
|
||||
//this.canGoForward = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -124,92 +117,92 @@ export class StreamOverlayComponent implements OnInit, OnDestroy {
|
|||
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
this.refreshFocused = false;
|
||||
|
||||
if(this.thread){
|
||||
this.appThread.refresh();
|
||||
} else if(this.hashtagElement){
|
||||
this.appHashtag.refresh();
|
||||
} else if(this.accountName){
|
||||
this.appUserProfile.refresh();
|
||||
}
|
||||
this.loadedElements[this.visibleElementIndex].refresh();
|
||||
return false;
|
||||
}
|
||||
|
||||
goToTop(): boolean {
|
||||
this.loadedElements[this.visibleElementIndex].goToTop();
|
||||
return false;
|
||||
}
|
||||
|
||||
browseAccount(accountName: string): void {
|
||||
if(!accountName) return;
|
||||
if (!accountName) return;
|
||||
|
||||
this.nextElements.length = 0;
|
||||
if (this.currentElement) {
|
||||
this.previousElements.push(this.currentElement);
|
||||
}
|
||||
const newElement = new OverlayBrowsing(null, accountName, null);
|
||||
this.loadElement(newElement);
|
||||
//this.canGoForward = false;
|
||||
}
|
||||
|
||||
browseHashtag(hashtag: string): void {
|
||||
if(!hashtag) return;
|
||||
|
||||
this.nextElements.length = 0;
|
||||
if (this.currentElement) {
|
||||
this.previousElements.push(this.currentElement);
|
||||
}
|
||||
if (!hashtag) return;
|
||||
|
||||
const selectedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
const hashTagElement = new StreamElement(StreamTypeEnum.tag, hashtag, selectedAccount.id, hashtag, null, null, selectedAccount.instance);
|
||||
const newElement = new OverlayBrowsing(hashTagElement, null, null);
|
||||
this.loadElement(newElement);
|
||||
// this.canGoForward = false;
|
||||
}
|
||||
|
||||
browseThread(openThread: OpenThreadEvent): any {
|
||||
if(!openThread) return;
|
||||
|
||||
this.nextElements.length = 0;
|
||||
if (this.currentElement) {
|
||||
this.previousElements.push(this.currentElement);
|
||||
}
|
||||
if (!openThread) return;
|
||||
|
||||
const newElement = new OverlayBrowsing(null, null, openThread);
|
||||
this.loadElement(newElement);
|
||||
//this.canGoForward = false;
|
||||
}
|
||||
|
||||
private loadElement(element: OverlayBrowsing) {
|
||||
|
||||
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
this.refreshFocused = false;
|
||||
this.refreshFocused = false;
|
||||
|
||||
this.currentElement = element;
|
||||
if (this.visibleElementIndex >= 0) {
|
||||
this.loadedElements[this.visibleElementIndex].hide();
|
||||
this.loadedElements = this.loadedElements.slice(0, this.visibleElementIndex + 1);
|
||||
}
|
||||
|
||||
this.accountName = this.currentElement.account;
|
||||
this.thread = this.currentElement.thread;
|
||||
this.hashtagElement = this.currentElement.hashtag;
|
||||
this.visibleElementIndex = this.visibleElementIndex + 1;
|
||||
this.loadedElements.push(element)
|
||||
this.loadedElements[this.visibleElementIndex].show();
|
||||
|
||||
this.hasPreviousElements = this.visibleElementIndex > 0;
|
||||
this.hasNextElements = false;
|
||||
}
|
||||
}
|
||||
|
||||
class OverlayBrowsing {
|
||||
class OverlayBrowsing {
|
||||
refreshEventEmitter = new EventEmitter();
|
||||
goToTopEventEmitter = new EventEmitter();
|
||||
|
||||
constructor(
|
||||
public readonly hashtag: StreamElement,
|
||||
public readonly account: string,
|
||||
public readonly thread: OpenThreadEvent) {
|
||||
|
||||
if (hashtag) {
|
||||
this.type = OverlayEnum.hashtag;
|
||||
this.type = 'hashtag';
|
||||
} else if (account) {
|
||||
this.type = OverlayEnum.account;
|
||||
this.type = 'account';
|
||||
} else if (thread) {
|
||||
this.type = OverlayEnum.thread;
|
||||
this.type = 'thread';
|
||||
} else {
|
||||
throw Error('NotImplemented');
|
||||
}
|
||||
}
|
||||
|
||||
type: OverlayEnum;
|
||||
}
|
||||
show(): any {
|
||||
setTimeout(() => {
|
||||
this.isVisible = true;
|
||||
}, 200);
|
||||
}
|
||||
hide(): any {
|
||||
this.isVisible = false;
|
||||
}
|
||||
refresh(): any {
|
||||
this.refreshEventEmitter.next();
|
||||
}
|
||||
goToTop(): any {
|
||||
this.goToTopEventEmitter.next();
|
||||
}
|
||||
|
||||
enum OverlayEnum {
|
||||
unknown = 0,
|
||||
hashtag = 1,
|
||||
account = 2,
|
||||
thread = 3
|
||||
isVisible: boolean;
|
||||
type: 'hashtag' | 'account' | 'thread';
|
||||
}
|
||||
|
|
|
@ -175,10 +175,12 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
this.statuses.length = 2 * this.streamingService.nbStatusPerIteration;
|
||||
}
|
||||
const stream = this.statustream.nativeElement as HTMLElement;
|
||||
stream.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
setTimeout(() => {
|
||||
stream.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
<div class="stream-column">
|
||||
<div class="sliding-column" [class.sliding-column__right-display]="overlayActive">
|
||||
<app-stream-overlay class="stream-overlay" *ngIf="overlayActive"
|
||||
(closeOverlay)="closeOverlay()"
|
||||
[browseAccountData]="overlayAccountToBrowse"
|
||||
[browseHashtagData]="overlayHashtagToBrowse"
|
||||
[browseThreadData]="overlayThreadToBrowse"></app-stream-overlay>
|
||||
|
||||
<app-stream-overlay class="stream-overlay" *ngIf="overlayActive" (closeOverlay)="closeOverlay()"
|
||||
[browseAccountData]="overlayAccountToBrowse" [browseHashtagData]="overlayHashtagToBrowse"
|
||||
[browseThreadData]="overlayThreadToBrowse"></app-stream-overlay>
|
||||
<!-- <div> -->
|
||||
<div class="stream-column__stream-header">
|
||||
<a class="stream-column__stream-selector" href title="return to top" (click)="goToTop()">
|
||||
<fa-icon class="stream-column__stream-selector--icon" [icon]="columnFaIcon"></fa-icon>
|
||||
<h1 class="stream-column__stream-selector--title">{{ streamElement.name.toUpperCase() }}</h1>
|
||||
<span class="stream-column__stream-selector--subtitle"
|
||||
*ngIf="streamElement.instance">{{ streamElement.instance.toLowerCase() }}</span>
|
||||
</a>
|
||||
<a class="stream-column__open-menu" href title="edit column" (click)="openEditionMenu()">
|
||||
<fa-icon class="stream-column__open-menu--icon" [icon]="menuFaIcon"></fa-icon>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="stream-column__stream-header">
|
||||
<a class="stream-column__stream-selector" href title="return to top" (click)="goToTop()">
|
||||
<fa-icon class="stream-column__stream-selector--icon" [icon]="columnFaIcon"></fa-icon>
|
||||
<h1 class="stream-column__stream-selector--title">{{ streamElement.name.toUpperCase() }}</h1>
|
||||
<span class="stream-column__stream-selector--subtitle"
|
||||
*ngIf="streamElement.instance">{{ streamElement.instance.toLowerCase() }}</span>
|
||||
</a>
|
||||
<a class="stream-column__open-menu" href title="edit column" (click)="openEditionMenu()">
|
||||
<fa-icon class="stream-column__open-menu--icon" [icon]="menuFaIcon"></fa-icon>
|
||||
</a>
|
||||
<app-stream-edition class="stream-edition" *ngIf="editionPanelIsOpen" [streamElement]="streamElement"
|
||||
(closed)="streamEditionClosed()">
|
||||
</app-stream-edition>
|
||||
|
||||
<app-stream-statuses class="stream-statuses" [streamElement]="streamElement"
|
||||
[goToTop]="goToTopSubject.asObservable()" (browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)">
|
||||
</app-stream-statuses>
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
|
||||
<app-stream-edition class="stream-edition" *ngIf="editionPanelIsOpen"
|
||||
[streamElement]="streamElement"
|
||||
(closed)="streamEditionClosed()">
|
||||
</app-stream-edition>
|
||||
|
||||
<app-stream-statuses class="stream-statuses"
|
||||
[streamElement]="streamElement"
|
||||
[goToTop]="goToTopSubject.asObservable()"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-stream-statuses>
|
||||
</div>
|
|
@ -1,5 +1,6 @@
|
|||
@import "variables";
|
||||
@import "commons";
|
||||
@import "panel";
|
||||
|
||||
.stream-edition {
|
||||
width: $stream-column-width;
|
||||
|
@ -11,9 +12,13 @@
|
|||
position: relative;
|
||||
width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
overflow: hidden;
|
||||
background-color: $column-color;
|
||||
margin: 0 0 0 $stream-column-separator;
|
||||
|
||||
&__stream-header {
|
||||
position: relative;
|
||||
width: $stream-column-width;
|
||||
border-bottom: 1px solid #222736;
|
||||
}
|
||||
&__open-menu {
|
||||
|
@ -37,7 +42,7 @@
|
|||
}
|
||||
&__stream-selector {
|
||||
display: block;
|
||||
width: calc(100%);
|
||||
width: $stream-column-width;
|
||||
height: $stream-header-height;
|
||||
background-color: $column-header-background-color;
|
||||
text-decoration: none;
|
||||
|
@ -74,6 +79,14 @@
|
|||
width: 320px;
|
||||
}
|
||||
|
||||
|
||||
// .stream-overlay {
|
||||
// float: right;
|
||||
// width: $stream-column-width;
|
||||
// height: calc(100%);
|
||||
// }
|
||||
|
||||
|
||||
// .stream-toots {
|
||||
// height: calc(100% - 30px);
|
||||
// width: 320px;
|
||||
|
@ -83,9 +96,10 @@
|
|||
// border-width: 0 0 1px 0;
|
||||
// }
|
||||
// }
|
||||
.stream-overlay {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
}
|
||||
// .stream-overlay {
|
||||
// // position: absolute;
|
||||
// float: right;
|
||||
// //z-index: 100;
|
||||
// width: $stream-column-width;
|
||||
// height: calc(100%);
|
||||
// }
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter, ViewChildren, QueryList } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter, ViewChildren, QueryList, ViewChild, ElementRef } from '@angular/core';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
|
@ -28,6 +28,9 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
|
||||
|
||||
@Input() refreshEventEmitter: EventEmitter<any>;
|
||||
@Input() goToTopEventEmitter: EventEmitter<any>;
|
||||
|
||||
@Input('currentThread')
|
||||
set currentThread(thread: OpenThreadEvent) {
|
||||
if (thread) {
|
||||
|
@ -41,6 +44,8 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
private newPostSub: Subscription;
|
||||
private hideAccountSubscription: Subscription;
|
||||
private deleteStatusSubscription: Subscription;
|
||||
private refreshSubscription: Subscription;
|
||||
private goToTopSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private readonly notificationService: NotificationService,
|
||||
|
@ -48,26 +53,24 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
private readonly mastodonService: MastodonService) { }
|
||||
|
||||
ngOnInit() {
|
||||
if (this.refreshEventEmitter) {
|
||||
this.refreshSubscription = this.refreshEventEmitter.subscribe(() => {
|
||||
this.refresh();
|
||||
})
|
||||
}
|
||||
|
||||
if (this.goToTopEventEmitter) {
|
||||
this.goToTopSubscription = this.goToTopEventEmitter.subscribe(() => {
|
||||
this.goToTop();
|
||||
})
|
||||
}
|
||||
|
||||
this.newPostSub = this.notificationService.newRespondPostedStream.subscribe((replyData: NewReplyData) => {
|
||||
if(replyData){
|
||||
if (replyData) {
|
||||
const repondingStatus = this.statuses.find(x => x.status.id === replyData.uiStatusId);
|
||||
const responseStatus = replyData.response;
|
||||
if(repondingStatus && this.statuses[0]){
|
||||
if (repondingStatus && this.statuses[0]) {
|
||||
this.statuses.push(responseStatus);
|
||||
|
||||
// const uiProvider = this.statuses[0].provider;
|
||||
// if(uiProvider.id === responseStatus.provider.id){
|
||||
|
||||
// } else {
|
||||
// this.toolsService.getStatusUsableByAccount(uiProvider, responseStatus)
|
||||
// .then((status: Status) => {
|
||||
// this.statuses.push(new StatusWrapper(status, uiProvider));
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// this.notificationService.notifyHttpError(err);
|
||||
// });
|
||||
// }
|
||||
// this.getThread(this.statuses[0].provider, this.lastThreadEvent);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -75,7 +78,7 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
this.hideAccountSubscription = this.notificationService.hideAccountUrlStream.subscribe((accountUrl: string) => {
|
||||
if (accountUrl) {
|
||||
this.statuses = this.statuses.filter(x => {
|
||||
if(x.status.reblog){
|
||||
if (x.status.reblog) {
|
||||
return x.status.reblog.account.url != accountUrl;
|
||||
} else {
|
||||
return x.status.account.url != accountUrl;
|
||||
|
@ -85,9 +88,9 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
|
||||
this.deleteStatusSubscription = this.notificationService.deletedStatusStream.subscribe((status: StatusWrapper) => {
|
||||
if(status){
|
||||
if (status) {
|
||||
this.statuses = this.statuses.filter(x => {
|
||||
return !(x.status.url.replace('https://','').split('/')[0] === status.provider.instance && x.status.id === status.status.id);
|
||||
return !(x.status.url.replace('https://', '').split('/')[0] === status.provider.instance && x.status.id === status.status.id);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -97,6 +100,19 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
if (this.newPostSub) this.newPostSub.unsubscribe();
|
||||
if (this.hideAccountSubscription) this.hideAccountSubscription.unsubscribe();
|
||||
if (this.deleteStatusSubscription) this.deleteStatusSubscription.unsubscribe();
|
||||
if (this.refreshSubscription) this.refreshSubscription.unsubscribe();
|
||||
if (this.goToTopSubscription) this.goToTopSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
@ViewChild('statusstream') public statustream: ElementRef;
|
||||
goToTop(): any {
|
||||
const stream = this.statustream.nativeElement as HTMLElement;
|
||||
setTimeout(() => {
|
||||
stream.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private getThread(openThreadEvent: OpenThreadEvent) {
|
||||
|
@ -139,6 +155,7 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
return this.mastodonService.getStatusContext(currentAccount, status.id)
|
||||
.then((context: Context) => {
|
||||
let contextStatuses = [...context.ancestors, status, ...context.descendants]
|
||||
const position = context.ancestors.length;
|
||||
|
||||
for (const s of contextStatuses) {
|
||||
const wrapper = new StatusWrapper(s, currentAccount);
|
||||
|
@ -146,9 +163,21 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
this.hasContentWarnings = this.statuses.filter(x => x.status.sensitive || x.status.spoiler_text).length > 1;
|
||||
|
||||
return position;
|
||||
});
|
||||
|
||||
})
|
||||
.then((position: number) => {
|
||||
setTimeout(() => {
|
||||
const el = this.statusChildren.toArray()[position];
|
||||
el.isSelected = true;
|
||||
// el.elem.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
|
||||
// el.elem.nativeElement.scrollIntoView({ behavior: 'auto', block: 'start', inline: 'nearest' });
|
||||
// el.elem.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
|
||||
el.elem.nativeElement.scrollIntoViewIfNeeded({ behavior: 'auto', block: 'start', inline: 'nearest' });
|
||||
}, 0);
|
||||
})
|
||||
.catch((err: HttpErrorResponse) => {
|
||||
this.notificationService.notifyHttpError(err);
|
||||
})
|
||||
|
|
|
@ -55,6 +55,8 @@ export class UserProfileComponent implements OnInit {
|
|||
private accounts$: Observable<AccountInfo[]>;
|
||||
private accountSub: Subscription;
|
||||
private deleteStatusSubscription: Subscription;
|
||||
private refreshSubscription: Subscription;
|
||||
private goToTopSubscription: Subscription;
|
||||
|
||||
@ViewChild('statusstream') public statustream: ElementRef;
|
||||
@ViewChild('profilestatuses') public profilestatuses: ElementRef;
|
||||
|
@ -63,6 +65,9 @@ export class UserProfileComponent implements OnInit {
|
|||
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
|
||||
|
||||
@Input() refreshEventEmitter: EventEmitter<any>;
|
||||
@Input() goToTopEventEmitter: EventEmitter<any>;
|
||||
|
||||
@Input('currentAccount')
|
||||
set currentAccount(accountName: string) {
|
||||
this.load(accountName);
|
||||
|
@ -79,6 +84,18 @@ export class UserProfileComponent implements OnInit {
|
|||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.refreshEventEmitter) {
|
||||
this.refreshSubscription = this.refreshEventEmitter.subscribe(() => {
|
||||
this.refresh();
|
||||
})
|
||||
}
|
||||
|
||||
if (this.goToTopEventEmitter) {
|
||||
this.goToTopSubscription = this.goToTopEventEmitter.subscribe(() => {
|
||||
this.goToTop();
|
||||
})
|
||||
}
|
||||
|
||||
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
|
||||
if (this.displayedAccount) {
|
||||
const userAccount = accounts.filter(x => x.isSelected)[0];
|
||||
|
@ -104,11 +121,23 @@ export class UserProfileComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.accountSub.unsubscribe();
|
||||
this.deleteStatusSubscription.unsubscribe();
|
||||
if (this.accountSub) this.accountSub.unsubscribe();
|
||||
if (this.deleteStatusSubscription) this.deleteStatusSubscription.unsubscribe();
|
||||
if (this.refreshSubscription) this.refreshSubscription.unsubscribe();
|
||||
if (this.goToTopSubscription) this.goToTopSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
goToTop(): any {
|
||||
const stream = this.statustream.nativeElement as HTMLElement;
|
||||
setTimeout(() => {
|
||||
stream.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private load(accountName: string) {
|
||||
|
@ -219,6 +248,8 @@ export class UserProfileComponent implements OnInit {
|
|||
}
|
||||
|
||||
browseAccount(accountName: string): void {
|
||||
if(accountName === this.toolsService.getAccountFullHandle(this.displayedAccount)) return;
|
||||
|
||||
this.browseAccountEvent.next(accountName);
|
||||
}
|
||||
|
||||
|
@ -323,7 +354,7 @@ export class UserProfileComponent implements OnInit {
|
|||
|
||||
isSwitchingSection: boolean;
|
||||
switchStatusSection(section: 'status' | 'replies' | 'media'): boolean {
|
||||
this.isSwitchingSection = true;
|
||||
this.isSwitchingSection = true;
|
||||
|
||||
this.statusSection = section;
|
||||
this.statuses.length = 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="main-display flexcroll">
|
||||
<div class="main-display__stream-column" *ngFor="let s of streamElements$ | async">
|
||||
<app-stream [streamElement]="s" #stream></app-stream>
|
||||
<div class="main-display__stream-column" *ngFor="let s of streamElements$ | async" #stream>
|
||||
<app-stream [streamElement]="s"></app-stream>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
overflow-y: hidden;
|
||||
&__stream-column {
|
||||
height: calc(100%);
|
||||
width: $stream-column-width + $stream-column-separator;
|
||||
width: calc(#{$stream-column-width} + #{$stream-column-separator});
|
||||
display: inline-block;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
white-space: normal;
|
||||
// margin: 0 0 0 $stream-column-separator;
|
||||
margin: 0;
|
||||
// border: 1px solid greenyellow;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,4 +10,26 @@
|
|||
text-transform: uppercase;
|
||||
margin: 4px 0 12px 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sliding-column {
|
||||
transition: all .25s;
|
||||
transition-timing-function: ease-out;
|
||||
|
||||
width: calc(2 * #{$stream-column-width});
|
||||
height: calc(100%);
|
||||
position: relative;
|
||||
left: 0;
|
||||
|
||||
&__right-display {
|
||||
transition-timing-function: ease-out;
|
||||
position: relative;
|
||||
left: -$stream-column-width;
|
||||
}
|
||||
}
|
||||
|
||||
.stream-overlay {
|
||||
float: right;
|
||||
width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue