1
0
mirror of https://github.com/NicolasConstant/sengi synced 2025-01-31 10:44:55 +01:00

Merge pull request #15 from NicolasConstant/feature_reponse-to-status

Feature reponse to status
This commit is contained in:
Nicolas Constant 2018-10-19 23:44:41 -04:00 committed by GitHub
commit 932375f8e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 201 additions and 18 deletions

View File

@ -34,6 +34,7 @@ import { AddNewStatusComponent } from "./components/floating-column/add-new-stat
import { ManageAccountComponent } from "./components/floating-column/manage-account/manage-account.component";
import { ActionBarComponent } from './components/stream/status/action-bar/action-bar.component';
import { WaitingAnimationComponent } from './components/waiting-animation/waiting-animation.component';
import { ReplyToStatusComponent } from './components/stream/status/reply-to-status/reply-to-status.component';
const routes: Routes = [
{ path: "", redirectTo: "home", pathMatch: "full" },
@ -60,7 +61,8 @@ const routes: Routes = [
AddNewAccountComponent,
SearchComponent,
ActionBarComponent,
WaitingAnimationComponent
WaitingAnimationComponent,
ReplyToStatusComponent
],
imports: [
BrowserModule,

View File

@ -3,10 +3,9 @@
<form (ngSubmit)="onSubmit()">
<!-- <label>Please provide your account:</label> -->
<input [(ngModel)]="title" type="text" class="form-control form-control-sm" name="title" autocomplete="off"
placeholder="Title (optional)" />
<input [(ngModel)]="title" type="text" class="form-control form-control-sm" name="title" autocomplete="off" placeholder="Title (optional)" />
<!-- <textarea rows="4" cols="50"> -->
<textarea [(ngModel)]="status" name="status" class="form-control form-control-sm" style="min-width: 100%" rows="5" required placeholder="What's in your mind?" (keydown.control.enter)="onCtrlEnter()"></textarea>
<textarea #reply [(ngModel)]="status" name="status" class="form-control form-control-sm" style="min-width: 100%" rows="5" required placeholder="What's in your mind?" (keydown.control.enter)="onCtrlEnter()"></textarea>
<select class="form-control form-control-sm form-control--privacy" id="privacy" name="privacy" [(ngModel)]="selectedPrivacy">
<option *ngFor="let p of privacyList" [ngValue]="p">{{p}}</option>

View File

@ -1,4 +1,4 @@
import { Component, OnInit, Input } from '@angular/core';
import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core';
import { Store } from '@ngxs/store';
import { AccountInfo } from '../../../states/accounts.state';
import { MastodonService, VisibilityEnum } from '../../../services/mastodon.service';
@ -13,14 +13,19 @@ import { FormsModule } from '@angular/forms';
export class AddNewStatusComponent implements OnInit {
@Input() title: string;
@Input() status: string;
@ViewChild('reply') replyElement: ElementRef;
selectedPrivacy = 'Public';
privacyList: string[] = ['Public', 'Unlisted', 'Follows-only', 'DM'];
constructor(private readonly store: Store,
constructor(
private readonly store: Store,
private readonly mastodonService: MastodonService) { }
ngOnInit() {
setTimeout(() => {
this.replyElement.nativeElement.focus();
}, 0);
}
onSubmit(): boolean {

View File

@ -1,10 +1,10 @@
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
import { Store } from '@ngxs/store';
import { Observable, Subscription } from 'rxjs';
import { StatusWrapper } from '../../stream.component';
import { MastodonService } from '../../../../services/mastodon.service';
import { AccountInfo } from '../../../../states/accounts.state';
import { Observable, Subscription } from 'rxjs';
import { Status, Results } from '../../../../services/models/mastodon.interfaces';
// import { map } from "rxjs/operators";
@ -16,6 +16,7 @@ import { Status, Results } from '../../../../services/models/mastodon.interfaces
export class ActionBarComponent implements OnInit, OnDestroy {
@Input() statusWrapper: StatusWrapper;
@Output() replyEvent = new EventEmitter();
isFavorited: boolean;
isBoosted: boolean;
@ -80,7 +81,7 @@ export class ActionBarComponent implements OnInit, OnDestroy {
}
reply(): boolean {
console.warn('reply');
this.replyEvent.emit();
return false;
}

View File

@ -0,0 +1,8 @@
<form (ngSubmit)="onSubmit()">
<textarea #reply [(ngModel)]="status" name="status" class="form-control form-control-sm" rows="5" required placeholder="What's in your mind?" (keydown.control.enter)="onCtrlEnter()"></textarea>
<select class="form-control form-control-sm form-control--privacy" id="privacy" name="privacy" [(ngModel)]="selectedPrivacy">
<option *ngFor="let p of privacyList" [ngValue]="p">{{p}}</option>
</select>
<button type="submit" class="btn btn-sm btn-custom-primary">REPLY!</button>
</form>

View File

@ -0,0 +1,36 @@
@import "variables";
@import "panel";
@import "buttons";
$btn-send-status-width: 60px;
.form-control {
margin: 0 0 5px 5px;
width: calc(100% - 10px);
background-color: $column-color;
border-color: $status-secondary-color;
color: #fff;
font-size: $default-font-size;
&:focus {
box-shadow: none;
}
&--privacy {
display: inline-block;
width: calc(100% - 15px - #{$btn-send-status-width});
}
}
.btn-custom-primary {
display: inline-block;
width: $btn-send-status-width;
position: relative;
top: -1px;
left: 5px; // background-color: orange;
// border-color: orange;
// color: black;
font-weight: 500; // &:hover {
// }
// &:focus {
// border-color: darkblue;
// }
}

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReplyToStatusComponent } from './reply-to-status.component';
describe('ReplyToStatusComponent', () => {
let component: ReplyToStatusComponent;
let fixture: ComponentFixture<ReplyToStatusComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ReplyToStatusComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ReplyToStatusComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,84 @@
import { Component, OnInit, Input, Output, EventEmitter, ElementRef, ViewChild } from '@angular/core';
import { Store } from '@ngxs/store';
import { MastodonService, VisibilityEnum } from '../../../../services/mastodon.service';
import { AccountInfo } from '../../../../states/accounts.state';
import { StatusWrapper } from '../../stream.component';
import { Status } from '../../../../services/models/mastodon.interfaces';
@Component({
selector: 'app-reply-to-status',
templateUrl: './reply-to-status.component.html',
styleUrls: ['./reply-to-status.component.scss']
})
export class ReplyToStatusComponent implements OnInit {
@Input() status: string = '';
@Input() statusReplyingToWrapper: StatusWrapper;
@Output() onClose = new EventEmitter();
@ViewChild('reply') replyElement: ElementRef;
private statusReplyingTo: Status;
selectedPrivacy = 'Public';
privacyList: string[] = ['Public', 'Unlisted', 'Follows-only', 'DM'];
constructor(
private readonly store: Store,
private readonly mastodonService: MastodonService) { }
ngOnInit() {
this.statusReplyingTo = this.statusReplyingToWrapper.status;
this.status += `@${this.statusReplyingTo.account.acct} `;
for (const mention of this.statusReplyingTo.mentions) {
this.status += `@${mention.acct} `;
}
setTimeout(() => {
this.replyElement.nativeElement.focus();
}, 0);
}
onSubmit(): boolean {
const accounts = this.getRegisteredAccounts();
const selectedAccounts = accounts.filter(x => x.isSelected);
let visibility: VisibilityEnum = VisibilityEnum.Unknown;
switch (this.selectedPrivacy) {
case 'Public':
visibility = VisibilityEnum.Public;
break;
case 'Unlisted':
visibility = VisibilityEnum.Unlisted;
break;
case 'Follows-only':
visibility = VisibilityEnum.Private;
break;
case 'DM':
visibility = VisibilityEnum.Direct;
break;
}
let spoiler = this.statusReplyingTo.spoiler_text;
for (const acc of selectedAccounts) {
this.mastodonService.postNewStatus(acc, this.status, visibility, spoiler, this.statusReplyingTo.id)
.then((res: Status) => {
console.log(res);
this.status = '';
this.onClose.emit();
});
}
return false;
}
private getRegisteredAccounts(): AccountInfo[] {
var regAccounts = <AccountInfo[]>this.store.snapshot().registeredaccounts.accounts;
return regAccounts;
}
onCtrlEnter(): boolean {
this.onSubmit();
return false;
}
}

View File

@ -18,5 +18,7 @@
<app-attachements *ngIf="hasAttachments" class="attachments" [attachments]="displayedStatus.media_attachments"></app-attachements>
<app-action-bar [statusWrapper]="statusWrapper"></app-action-bar>
<app-action-bar [statusWrapper]="statusWrapper" (replyEvent)="openReply()"></app-action-bar>
<app-reply-to-status *ngIf="replyingToStatus" [statusReplyingToWrapper]="statusWrapper" (onClose)="closeReply()"></app-reply-to-status>
</div>

View File

@ -1,4 +1,4 @@
import { Component, OnInit, Input, Inject, LOCALE_ID } from "@angular/core";
import { Component, OnInit, Input, Inject, LOCALE_ID, ElementRef } from "@angular/core";
import { Status } from "../../../services/models/mastodon.interfaces";
import { formatDate } from '@angular/common';
import { stateNameErrorMessage } from "@ngxs/store/src/decorators/state";
@ -14,6 +14,7 @@ export class StatusComponent implements OnInit {
displayedStatus: Status;
reblog: boolean;
hasAttachments: boolean;
replyingToStatus: boolean;
private _statusWrapper: StatusWrapper;
status: Status;
@ -44,7 +45,8 @@ export class StatusComponent implements OnInit {
}
constructor(@Inject(LOCALE_ID) private locale: string) { }
constructor(
@Inject(LOCALE_ID) private locale: string) { }
ngOnInit() {
}
@ -66,4 +68,15 @@ export class StatusComponent implements OnInit {
return formatDate(date, 'MM/dd', this.locale);
}
openReply(): boolean{
this.replyingToStatus = !this.replyingToStatus;
return false;
}
closeReply(): boolean {
this.replyingToStatus = false;
return false;
}
}

View File

@ -2,7 +2,7 @@
.stream-column {
width: $stream-column-width;
height: calc(100%);
background-color: #0f111a;
background-color: $column-color;
margin: 0 0 0 $stream-column-separator;
&__stream-header {
width: calc(100%);

View File

@ -122,10 +122,12 @@ export interface Status {
spoiler_text: string;
visibility: string;
media_attachments: Attachment[];
mentions: string;
tags: string;
mentions: Mention[];
tags: Tag[];
application: Application;
emojis: any[];
language: string;
pinned: boolean;
}
export interface Tag {
name: string;

View File

@ -4,16 +4,22 @@ $font-link-primary: #595c67;
$font-link-primary-hover: #8f93a2;
$color-primary: #141824;
$color-secondary: #090b10;
$column-color: #0f111a;
$default-font-size: 15px;
$small-font-size: 12px;
$btn-primary-color: #515a62;
$btn-primary-color: #254d6f;
// $btn-primary-color: #515a62;
// $btn-primary-color: #254d6f;
$btn-primary-color: #444f74;
$btn-primary-color-hover: darken($btn-primary-color, 10);
$btn-primary-font-color: white;
// TEST 1
$status-primary-color: #fff;
$status-secondary-color: #353e64;
// $status-secondary-color: #353e64;
$status-secondary-color: #4e5572;
$status-links-color: #d9e1e8;
// $status-primary-color : #8f93a2;