|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "sengi",
|
||||
"version": "0.7.0",
|
||||
"version": "0.9.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -6327,11 +6327,6 @@
|
|||
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
|
||||
"dev": true
|
||||
},
|
||||
"ionicons": {
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-4.5.5.tgz",
|
||||
"integrity": "sha512-dIGI73XG6Fg2Ps77ry5Ywe36Pq7wUGkDkl0pBhC4uhsiyoW+oXe+pplmarXEnKEcB5fmlkRrBOxYYzZaoRiUGw=="
|
||||
},
|
||||
"ip": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "sengi",
|
||||
"version": "0.9.0",
|
||||
"version": "0.9.1",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "main-electron.js",
|
||||
"description": "A multi-account desktop client for Mastodon and Pleroma",
|
||||
|
@ -15,6 +15,7 @@
|
|||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"start-mem": "node --max_old_space_size=5048 ./node_modules/@angular/cli/bin/ng serve",
|
||||
"build": "ng build --prod",
|
||||
"test": "ng test",
|
||||
"test-nowatch": "ng test --watch=false",
|
||||
|
@ -44,8 +45,7 @@
|
|||
"@ngxs/store": "^3.2.0",
|
||||
"bootstrap": "^4.1.3",
|
||||
"core-js": "^2.5.4",
|
||||
"emojione": "^4.5.0",
|
||||
"ionicons": "^4.4.3",
|
||||
"emojione": "~4.5.0",
|
||||
"rxjs": "^6.4.0",
|
||||
"tslib": "^1.9.0",
|
||||
"zone.js": "^0.8.29"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<form (ngSubmit)="onSubmit()">
|
||||
<label>Please provide your account:</label>
|
||||
<input type="text" class="form-control form-control-sm" [(ngModel)]="mastodonFullHandle" name="mastodonFullHandle"
|
||||
<input type="text" class="form-control form-control-sm form-color" [(ngModel)]="mastodonFullHandle" name="mastodonFullHandle"
|
||||
placeholder="@nickname@mastodon.social" />
|
||||
<br />
|
||||
<button type="submit" class="btn btn-success btn-sm">Submit</button>
|
||||
|
|
|
@ -1,2 +1,14 @@
|
|||
@import "variables";
|
||||
@import "panel";
|
||||
@import "panel";
|
||||
|
||||
.form-color {
|
||||
background-color: $column-color;
|
||||
border-color: $button-border-color;
|
||||
color: #fff;
|
||||
font-size: $default-font-size;
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
height: 29px;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
|
@ -13,6 +13,8 @@ import { NotificationService } from '../../../services/notification.service';
|
|||
styleUrls: ['./add-new-account.component.scss']
|
||||
})
|
||||
export class AddNewAccountComponent implements OnInit {
|
||||
private blockList = ['gab.com', 'gab.ai'];
|
||||
|
||||
@Input() mastodonFullHandle: string;
|
||||
|
||||
constructor(
|
||||
|
@ -29,6 +31,8 @@ export class AddNewAccountComponent implements OnInit {
|
|||
const username = fullHandle[0];
|
||||
const instance = fullHandle[1];
|
||||
|
||||
this.checkBlockList(instance);
|
||||
|
||||
this.checkAndCreateApplication(instance)
|
||||
.then((appData: AppData) => {
|
||||
this.redirectToInstanceAuthPage(username, instance, appData);
|
||||
|
@ -36,7 +40,7 @@ export class AddNewAccountComponent implements OnInit {
|
|||
.catch((err: HttpErrorResponse) => {
|
||||
if (err instanceof HttpErrorResponse) {
|
||||
this.notificationService.notifyHttpError(err);
|
||||
} else if ((<Error>err).message === 'CORS'){
|
||||
} else if ((<Error>err).message === 'CORS') {
|
||||
this.notificationService.notify('Connection Error. It\'s usually a CORS issue with the server you\'re connecting to. Please check in the console and if so, contact your administrator with those informations.', true);
|
||||
} else {
|
||||
this.notificationService.notify('Unkown error', true);
|
||||
|
@ -46,6 +50,20 @@ export class AddNewAccountComponent implements OnInit {
|
|||
return false;
|
||||
}
|
||||
|
||||
private checkBlockList(instance: string){
|
||||
let cleanInstance = instance.replace('http://', '').replace('https://', '').toLowerCase();
|
||||
for (let b of this.blockList) {
|
||||
if (cleanInstance == b || cleanInstance.includes(`.${b}`)) {
|
||||
let content = '<div style="width:100%; height:100%; background-color: black;"><iframe style="pointer-events: none;" width="100%" height="100%" src="https://www.youtube.com/embed/dQw4w9WgXcQ?rel=0&autoplay=1&showinfo=0&controls=0" allow="autoplay; fullscreen"></div>';
|
||||
|
||||
document.open();
|
||||
document.write(content);
|
||||
document.close();
|
||||
throw Error('Oh Noz!');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private checkAndCreateApplication(instance: string): Promise<AppData> {
|
||||
const alreadyRegisteredApps = this.getAllSavedApps();
|
||||
const instanceApps = alreadyRegisteredApps.filter(x => x.instance === instance);
|
||||
|
|
|
@ -21,7 +21,7 @@ export class MentionsComponent implements OnInit, OnDestroy {
|
|||
isLoading = false;
|
||||
isThread = false;
|
||||
hasContentWarnings = false;
|
||||
|
||||
|
||||
@Output() browseAccountEvent = new EventEmitter<string>();
|
||||
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
|
||||
|
@ -32,9 +32,9 @@ export class MentionsComponent implements OnInit, OnDestroy {
|
|||
this.loadMentions();
|
||||
}
|
||||
get account(): AccountWrapper {
|
||||
return this._account;
|
||||
return this._account;
|
||||
}
|
||||
|
||||
|
||||
@ViewChild('statusstream') public statustream: ElementRef;
|
||||
|
||||
private maxReached = false;
|
||||
|
@ -45,41 +45,48 @@ export class MentionsComponent implements OnInit, OnDestroy {
|
|||
constructor(
|
||||
private readonly notificationService: NotificationService,
|
||||
private readonly userNotificationService: UserNotificationService,
|
||||
private readonly mastodonService: MastodonService) {
|
||||
|
||||
}
|
||||
private readonly mastodonService: MastodonService) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if(this.userNotificationServiceSub){
|
||||
if (this.userNotificationServiceSub) {
|
||||
this.userNotificationServiceSub.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private loadMentions(){
|
||||
if(this.userNotificationServiceSub){
|
||||
private loadMentions() {
|
||||
if (this.userNotificationServiceSub) {
|
||||
this.userNotificationServiceSub.unsubscribe();
|
||||
}
|
||||
|
||||
this.statuses.length = 0;
|
||||
this.userNotificationService.markMentionsAsRead(this.account.info);
|
||||
this.userNotificationService.markMentionsAsRead(this.account.info);
|
||||
|
||||
this.userNotificationServiceSub = this.userNotificationService.userNotifications.subscribe((userNotifications: UserNotification[]) => {
|
||||
this.statuses.length = 0; //TODO: don't reset, only add the new ones
|
||||
const userNotification = userNotifications.find(x => x.account.id === this.account.info.id);
|
||||
if(userNotification && userNotification.mentions){
|
||||
userNotification.mentions.forEach((mention: Status) => {
|
||||
const statusWrapper = new StatusWrapper(mention, this.account.info);
|
||||
this.statuses.push(statusWrapper);
|
||||
});
|
||||
}
|
||||
this.lastId = userNotification.lastId;
|
||||
this.userNotificationService.markMentionsAsRead(this.account.info);
|
||||
this.processNewMentions(userNotifications);
|
||||
if(this.statuses.length < 20) this.scrolledToBottom();
|
||||
});
|
||||
}
|
||||
|
||||
private processNewMentions(userNotifications: UserNotification[]) {
|
||||
const userNotification = userNotifications.find(x => x.account.id === this.account.info.id);
|
||||
if (userNotification && userNotification.mentions) {
|
||||
let orderedMentions = [...userNotification.mentions].reverse();
|
||||
for (let m of orderedMentions) {
|
||||
if (!this.statuses.find(x => x.status.id === m.id)) {
|
||||
const statusWrapper = new StatusWrapper(m, this.account.info);
|
||||
this.statuses.unshift(statusWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.lastId = userNotification.lastId;
|
||||
this.userNotificationService.markMentionsAsRead(this.account.info);
|
||||
}
|
||||
|
||||
onScroll() {
|
||||
var element = this.statustream.nativeElement as HTMLElement;
|
||||
const atBottom = element.scrollHeight <= element.clientHeight + element.scrollTop + 1000;
|
||||
|
@ -102,7 +109,7 @@ export class MentionsComponent implements OnInit, OnDestroy {
|
|||
this.maxReached = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (const s of statuses) {
|
||||
const wrapper = new StatusWrapper(s, this.account.info);
|
||||
this.statuses.push(wrapper);
|
||||
|
@ -117,7 +124,7 @@ export class MentionsComponent implements OnInit, OnDestroy {
|
|||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
browseAccount(accountName: string): void {
|
||||
this.browseAccountEvent.next(accountName);
|
||||
}
|
||||
|
|
|
@ -68,19 +68,26 @@ export class NotificationsComponent implements OnInit, OnDestroy {
|
|||
this.userNotificationService.markNotificationAsRead(this.account.info);
|
||||
|
||||
this.userNotificationServiceSub = this.userNotificationService.userNotifications.subscribe((userNotifications: UserNotification[]) => {
|
||||
this.notifications.length = 0; //TODO: don't reset, only add the new ones
|
||||
const userNotification = userNotifications.find(x => x.account.id === this.account.info.id);
|
||||
if(userNotification && userNotification.notifications){
|
||||
userNotification.notifications.forEach((notification: Notification) => {
|
||||
const notificationWrapper = new NotificationWrapper(notification, this.account.info);
|
||||
this.notifications.push(notificationWrapper);
|
||||
});
|
||||
}
|
||||
this.lastId = userNotification.lastId;
|
||||
this.userNotificationService.markNotificationAsRead(this.account.info);
|
||||
this.processNewNotifications(userNotifications);
|
||||
if(this.notifications.length < 20) this.scrolledToBottom();
|
||||
});
|
||||
}
|
||||
|
||||
private processNewNotifications(userNotifications: UserNotification[]) {
|
||||
const userNotification = userNotifications.find(x => x.account.id === this.account.info.id);
|
||||
if (userNotification && userNotification.notifications) {
|
||||
let orderedNotifications = [...userNotification.notifications].reverse();
|
||||
for (let n of orderedNotifications) {
|
||||
const notificationWrapper = new NotificationWrapper(n, this.account.info);
|
||||
if (!this.notifications.find(x => x.wrapperId === notificationWrapper.wrapperId)) {
|
||||
this.notifications.unshift(notificationWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.lastId = userNotification.lastId;
|
||||
this.userNotificationService.markNotificationAsRead(this.account.info);
|
||||
}
|
||||
|
||||
|
||||
onScroll() {
|
||||
var element = this.statustream.nativeElement as HTMLElement;
|
||||
|
@ -150,9 +157,11 @@ class NotificationWrapper {
|
|||
this.status= new StatusWrapper(notification.status, provider);
|
||||
break;
|
||||
}
|
||||
this.account = notification.account;
|
||||
this.account = notification.account;
|
||||
this.wrapperId = `${this.type}-${notification.id}`;
|
||||
}
|
||||
|
||||
wrapperId: string;
|
||||
account: Account;
|
||||
status: StatusWrapper;
|
||||
type: 'mention' | 'reblog' | 'favourite' | 'follow';
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
<div class="left-bar">
|
||||
<a class="left-bar-button left-bar-button--status left-bar-link" href title="write new message" (click)="createNewStatus()" (contextmenu)="createNewStatus()" *ngIf="hasAccounts">
|
||||
<a class="left-bar-button left-bar-button--status left-bar-link" href title="write new message"
|
||||
(click)="createNewStatus()" (contextmenu)="createNewStatus()" *ngIf="hasAccounts">
|
||||
<fa-icon [icon]="faCommentAlt"></fa-icon>
|
||||
<!-- <ion-icon name="md-send"></ion-icon> -->
|
||||
</a>
|
||||
<a class="left-bar-button left-bar-button--search left-bar-link" href title="search" (click)="openSearch()" (contextmenu)="openSearch()" *ngIf="hasAccounts">
|
||||
<ion-icon name="md-search"></ion-icon>
|
||||
<a class="left-bar-button left-bar-button--search left-bar-link" href title="search" (click)="openSearch()"
|
||||
(contextmenu)="openSearch()" *ngIf="hasAccounts">
|
||||
<fa-icon [icon]="faSearch"></fa-icon>
|
||||
</a>
|
||||
|
||||
<div *ngFor="let account of accounts">
|
||||
<app-account-icon [account]="account" (toogleAccountNotify)="onToogleAccountNotify($event)" (openMenuNotify)="onOpenMenuNotify($event)">
|
||||
<app-account-icon [account]="account" (toogleAccountNotify)="onToogleAccountNotify($event)"
|
||||
(openMenuNotify)="onOpenMenuNotify($event)">
|
||||
</app-account-icon>
|
||||
</div>
|
||||
|
||||
<a class="left-bar-button left-bar-button--add left-bar-link" [ngClass]="{'no-accounts': hasAccounts === false }" href title="add new account" (click)="addNewAccount()" (contextmenu)="addNewAccount()">
|
||||
<ion-icon name="md-add"></ion-icon>
|
||||
<a class="left-bar-button left-bar-button--add left-bar-link" [ngClass]="{'no-accounts': hasAccounts === false }"
|
||||
href title="add new account" (click)="addNewAccount()" (contextmenu)="addNewAccount()">
|
||||
<fa-icon [icon]="faPlus"></fa-icon>
|
||||
</a>
|
||||
|
||||
<a class="left-bar-button left-bar-button--cog left-bar-link" href title="settings" (click)="openSettings()" (contextmenu)="openSettings()" *ngIf="hasAccounts">
|
||||
<ion-icon name="md-cog"></ion-icon>
|
||||
<a class="left-bar-button left-bar-button--cog left-bar-link" href title="settings" (click)="openSettings()"
|
||||
(contextmenu)="openSettings()" *ngIf="hasAccounts">
|
||||
<fa-icon [icon]="faCog"></fa-icon>
|
||||
</a>
|
||||
</div>
|
|
@ -35,15 +35,16 @@ $height-button: 40px;
|
|||
&--search {
|
||||
// font-size: 28px;
|
||||
// font-size: 22px;
|
||||
font-size: 24px;
|
||||
padding: 5px 0 0 12px;
|
||||
font-size: 16px;
|
||||
padding: 5px 0 0 16px;
|
||||
}
|
||||
&--add {
|
||||
padding: 5px 0 5px 13px;
|
||||
font-size: 22px;
|
||||
padding: 2px 0 5px 18px;
|
||||
font-size: 14px;
|
||||
}
|
||||
&--cog {
|
||||
padding: 2px 0 0 9px;
|
||||
font-size: 24px;
|
||||
padding: 5px 0 0 12px;
|
||||
position: absolute;
|
||||
bottom: 7px;
|
||||
opacity: .3;
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Component, OnInit, OnDestroy } from "@angular/core";
|
|||
import { HttpErrorResponse } from "@angular/common/http";
|
||||
import { Subscription, Observable } from "rxjs";
|
||||
import { Store } from "@ngxs/store";
|
||||
import { faPlus, faCog, faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCommentAlt } from "@fortawesome/free-regular-svg-icons";
|
||||
|
||||
import { Account } from "../../services/models/mastodon.interfaces";
|
||||
|
@ -19,6 +20,10 @@ import { UserNotificationService, UserNotification } from '../../services/user-n
|
|||
})
|
||||
export class LeftSideBarComponent implements OnInit, OnDestroy {
|
||||
faCommentAlt = faCommentAlt;
|
||||
faSearch = faSearch;
|
||||
faPlus = faPlus;
|
||||
faCog = faCog;
|
||||
|
||||
|
||||
accounts: AccountWithNotificationWrapper[] = [];
|
||||
hasAccounts: boolean;
|
||||
|
|
|
@ -1,41 +1,33 @@
|
|||
<div class="action-bar">
|
||||
<a *ngIf="!isLocked" href class="action-bar__link" title="Reply" (click)="reply()">
|
||||
<ion-icon name="ios-undo"></ion-icon>
|
||||
<a *ngIf="!isLocked" href class="action-bar__link action-bar__link--reply" title="Reply" (click)="reply()">
|
||||
<fa-icon [icon]="faReply"></fa-icon>
|
||||
</a>
|
||||
<ion-icon *ngIf="isLocked" class="action-bar__lock" name="lock" title="Account can't access this post"></ion-icon>
|
||||
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
|
||||
|
||||
<a *ngIf="!(isBoostLocked || isLocked)" href class="action-bar__link" title="Boost"
|
||||
[class.boosted]="isBoosted"
|
||||
[class.boosting]="boostIsLoading"
|
||||
(click)="boost()">
|
||||
<ion-icon name="md-swap"></ion-icon>
|
||||
<a *ngIf="!(isBoostLocked || isLocked)" href class="action-bar__link action-bar__link--boost" title="Boost" [class.boosted]="isBoosted"
|
||||
[class.boosting]="boostIsLoading" (click)="boost()">
|
||||
<fa-icon [icon]="faRetweet"></fa-icon>
|
||||
</a>
|
||||
<ion-icon *ngIf="isBoostLocked && !isLocked" class="action-bar__lock" name="lock"
|
||||
title="This post cannot be boosted"></ion-icon>
|
||||
<ion-icon *ngIf="isLocked" class="action-bar__lock" name="lock" title="Account can't access this post"></ion-icon>
|
||||
<fa-icon *ngIf="isBoostLocked && !isLocked" class="action-bar__lock" title="This post cannot be boosted"
|
||||
[icon]="faLock"></fa-icon>
|
||||
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
|
||||
|
||||
<a *ngIf="!isLocked" href class="action-bar__link" title="Favourite"
|
||||
[class.favorited]="isFavorited"
|
||||
[class.favoriting]="favoriteIsLoading"
|
||||
(click)="favorite()">
|
||||
<ion-icon name="md-star"></ion-icon>
|
||||
<a *ngIf="!isLocked" href class="action-bar__link action-bar__link--fav" title="Favourite" [class.favorited]="isFavorited"
|
||||
[class.favoriting]="favoriteIsLoading" (click)="favorite()">
|
||||
<fa-icon [icon]="faStar"></fa-icon>
|
||||
</a>
|
||||
<ion-icon *ngIf="isLocked" class="action-bar__lock" name="lock" title="Account can't access this post"></ion-icon>
|
||||
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
|
||||
|
||||
<a href class="action-bar__link action-bar__link--cw"
|
||||
title="show content" (click)="showContent()"
|
||||
<a href class="action-bar__link action-bar__link--cw" title="show content" (click)="showContent()"
|
||||
*ngIf="isContentWarningActive">
|
||||
<fa-icon class="action-bar__cw" [icon]="faWindowClose"></fa-icon>
|
||||
<fa-icon [icon]="faWindowClose"></fa-icon>
|
||||
</a>
|
||||
<a href class="action-bar__link action-bar__link--cw"
|
||||
title="hide content" (click)="hideContent()"
|
||||
<a href class="action-bar__link action-bar__link--cw" title="hide content" (click)="hideContent()"
|
||||
*ngIf="!isContentWarningActive">
|
||||
<fa-icon class="action-bar__cw" [icon]="faWindowCloseRegular"></fa-icon>
|
||||
<fa-icon [icon]="faWindowCloseRegular"></fa-icon>
|
||||
</a>
|
||||
|
||||
<a href class="action-bar__link action-bar__link--more" title="More" (click)="more()">
|
||||
<ion-icon name="ios-more"></ion-icon>
|
||||
</a>
|
||||
|
||||
|
||||
<!-- <a href class="action-bar__link action-bar__link--more" title="More" (click)="more()">
|
||||
<fa-icon [icon]="faEllipsisH"></fa-icon>
|
||||
</a> -->
|
||||
</div>
|
|
@ -4,9 +4,10 @@
|
|||
// outline: 1px solid greenyellow; // height: 20px;
|
||||
margin: 5px 10px 5px $avatar-column-space;
|
||||
padding: 0;
|
||||
font-size: 24px;
|
||||
font-size: 18px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
// transform: rotate(0.03deg);
|
||||
|
||||
&__link {
|
||||
color: $status-secondary-color;
|
||||
|
@ -19,36 +20,45 @@
|
|||
margin-right: 15px;
|
||||
}
|
||||
|
||||
|
||||
&--reply {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
&--boost {
|
||||
position: relative;
|
||||
bottom: -1px;
|
||||
// font-size: 22px;
|
||||
}
|
||||
|
||||
&--fav {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
&--cw {
|
||||
position: absolute;
|
||||
position: relative;
|
||||
bottom: -2px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
&--more {
|
||||
position: absolute;
|
||||
left: 155px;
|
||||
bottom: -6px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// &--more {
|
||||
// position: absolute;
|
||||
// left: 155px;
|
||||
// bottom: -6px;
|
||||
// }
|
||||
}
|
||||
|
||||
&__lock {
|
||||
color: $status-secondary-color;
|
||||
width: 24px;
|
||||
width: 22px;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
// &_cw {
|
||||
// // width: 18px;
|
||||
// font-size: 10px;
|
||||
|
||||
// &:not(:last-child) {
|
||||
// margin-right: 15px;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
.boosted {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angu
|
|||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { faWindowClose, faReply, faRetweet, faStar } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faWindowClose, faReply, faRetweet, faStar, faEllipsisH, faLock } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faWindowClose as faWindowCloseRegular } from "@fortawesome/free-regular-svg-icons";
|
||||
|
||||
import { MastodonService } from '../../../../services/mastodon.service';
|
||||
|
@ -23,6 +23,8 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||
faRetweet = faRetweet;
|
||||
faStar = faStar;
|
||||
faWindowCloseRegular = faWindowCloseRegular;
|
||||
faEllipsisH = faEllipsisH;
|
||||
faLock = faLock;
|
||||
|
||||
@Input() statusWrapper: StatusWrapper;
|
||||
@Output() replyEvent = new EventEmitter();
|
||||
|
|
|
@ -1,54 +1,62 @@
|
|||
import { Emoji } from "../services/models/mastodon.interfaces";
|
||||
import * as EmojiOne from "emojione";
|
||||
// import { EmojiOne } from "./emoji-one";
|
||||
import * as EmojiOne from 'emojione';
|
||||
|
||||
export class EmojiConverter {
|
||||
applyEmojis(emojis: Emoji[], text: string, type: EmojiTypeEnum): string {
|
||||
//const instanceUrl = 'https://' + url.split('https://')[1].split('/')[0];
|
||||
if(!text) return text;
|
||||
// private emojiOne = new EmojiOne();
|
||||
|
||||
let className = "emoji-small";
|
||||
if (type === EmojiTypeEnum.medium) {
|
||||
className = "emoji-medium";
|
||||
applyEmojis(emojis: Emoji[], text: string, type: EmojiTypeEnum): string {
|
||||
if (!text) return text;
|
||||
|
||||
let className = "emoji-small";
|
||||
if (type === EmojiTypeEnum.medium) {
|
||||
className = "emoji-medium";
|
||||
}
|
||||
|
||||
if (emojis) {
|
||||
emojis.forEach(emoji => {
|
||||
try {
|
||||
text = this.replaceAll(text, `:${emoji.shortcode}:`, `<img class="${className}" src="${emoji.url}" title=":${
|
||||
emoji.shortcode}:" alt=":${emoji.shortcode}:" />`);
|
||||
} catch (err) {}
|
||||
});
|
||||
}
|
||||
|
||||
text = this.applyEmojiOne(className, text);
|
||||
|
||||
// try {
|
||||
// text = this.emojiOne.toImage(text, className);
|
||||
// } catch (err) {}
|
||||
return text;
|
||||
}
|
||||
|
||||
if (emojis) {
|
||||
emojis.forEach(emoji => {
|
||||
text = text.replace(
|
||||
`:${emoji.shortcode}:`,
|
||||
`<img class="${className}" src="${emoji.url}" title=":${
|
||||
emoji.shortcode
|
||||
}:" alt=":${emoji.shortcode}:" />`
|
||||
);
|
||||
});
|
||||
private applyEmojiOne(className: string, text: string): string{
|
||||
text = EmojiOne.toImage(text);
|
||||
|
||||
while (text.includes('class="emojione"')) {
|
||||
text = text.replace('class="emojione"', `class="emojione ${className}"`);
|
||||
}
|
||||
|
||||
while (
|
||||
text.includes("https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/")
|
||||
) {
|
||||
text = text.replace(
|
||||
"https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/",
|
||||
"assets/emoji/72x72/"
|
||||
);
|
||||
// text = text.replace('.png', '.svg');
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
text = EmojiOne.toImage(text);
|
||||
|
||||
while (text.includes('class="emojione"')) {
|
||||
text = text.replace('class="emojione"', `class="emojione ${className}"`);
|
||||
private replaceAll(str, find, replace) {
|
||||
return str.replace(new RegExp(find, 'g'), replace);
|
||||
}
|
||||
|
||||
//FIXME: clean up this mess...
|
||||
// while (text.includes('https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/')) {
|
||||
// text = text.replace('https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/', instanceUrl + '/emoji/');
|
||||
// text = text.replace('.png', '.svg');
|
||||
// }
|
||||
|
||||
while (
|
||||
text.includes("https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/")
|
||||
) {
|
||||
text = text.replace(
|
||||
"https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/",
|
||||
"assets/emoji/72x72/"
|
||||
);
|
||||
// text = text.replace('.png', '.svg');
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
export enum EmojiTypeEnum {
|
||||
small,
|
||||
medium
|
||||
small,
|
||||
medium
|
||||
}
|
||||
|
||||
|
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 942 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.7 KiB |