Merge pull request #29 from NicolasConstant/feature_column-handling
Feature column handling
This commit is contained in:
commit
01619fd5a4
|
@ -647,6 +647,51 @@
|
|||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"@fortawesome/angular-fontawesome": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.3.0.tgz",
|
||||
"integrity": "sha512-wXvyPI7GidoNiqeMz2re9iemUMFH4zBmuv94CfXlaanQ8+kMP/fYs/k69PLVN1KsebQY4kRA9GHmc1U1ndBkJg==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.13.tgz",
|
||||
"integrity": "sha512-Qy1eMKylnbsCRXod8C4CfwqlNtLU7OkJiLsFJZlHY4rY9ky2VYUKNnRj0b+3lnGwA1dWNY+pI0XWbP/mrLCohw=="
|
||||
},
|
||||
"@fortawesome/fontawesome-svg-core": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.13.tgz",
|
||||
"integrity": "sha512-1Q0grmELVTBDbk/Jo4dRCptkYMQjikPEcoPo+eZS+oLVowv1afP4177m4gvqMwdk3l+9KYoiMBJzfY2qDbs+Dg==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.13"
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-brands-svg-icons": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.7.0.tgz",
|
||||
"integrity": "sha512-MA4FLVKfuamBlfkRznoAOHyCywGj0MToDyomvtpuJeB9BqNBPDQ/TpGTyRZ8TEyHqo8ejjjACXYjr2fIEB7FZA==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.13"
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-regular-svg-icons": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.7.0.tgz",
|
||||
"integrity": "sha512-q6u0JTCr8T8RDRYytVcPg/RvPXv67fVcxSa/pdF59OAF5scM03QakX+W+x0vuaWvrpUwU0VK2AXJzSYnBUNpJA==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.13"
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-solid-svg-icons": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.7.0.tgz",
|
||||
"integrity": "sha512-bWHNC9Mho8gJ/MFmnc+u6af0jXtdgNWdL6mxHE2lrPsSUGTBCr7AcYeTf+f0Q7JZDjIy/kW8FKpHcfuesScK5A==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.13"
|
||||
}
|
||||
},
|
||||
"@ngtools/webpack": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-6.1.1.tgz",
|
||||
|
|
12
package.json
12
package.json
|
@ -5,15 +5,14 @@
|
|||
"main": "main.js",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng build && electron .",
|
||||
"serve": "ng serve",
|
||||
"start": "ng serve",
|
||||
"build": "ng build --prod",
|
||||
"test": "ng test",
|
||||
"test-nowatch": "ng test --watch=false",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"electron": "ng build && electron .",
|
||||
"electron-prod": "ng build --prod && electron ."
|
||||
"electron": "ng build --prod && electron .",
|
||||
"electron-debug": "ng build && electron ."
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
|
@ -26,6 +25,11 @@
|
|||
"@angular/platform-browser": "^6.1.0",
|
||||
"@angular/platform-browser-dynamic": "^6.1.0",
|
||||
"@angular/router": "^6.1.0",
|
||||
"@fortawesome/angular-fontawesome": "^0.3.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.13",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.7.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.7.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.7.0",
|
||||
"@ngxs/storage-plugin": "^3.2.0",
|
||||
"@ngxs/store": "^3.2.0",
|
||||
"bootstrap": "^4.1.3",
|
||||
|
|
|
@ -10,6 +10,8 @@ import { NgxElectronModule } from "ngx-electron";
|
|||
import { NgxsModule } from '@ngxs/store';
|
||||
import { NgxsStoragePluginModule } from '@ngxs/storage-plugin';
|
||||
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
|
||||
import { AppComponent } from "./app.component";
|
||||
import { LeftSideBarComponent } from "./components/left-side-bar/left-side-bar.component";
|
||||
import { StreamsMainDisplayComponent } from "./pages/streams-main-display/streams-main-display.component";
|
||||
|
@ -42,6 +44,7 @@ import { StreamOverlayComponent } from './components/stream/stream-overlay/strea
|
|||
import { DatabindedTextComponent } from './components/stream/status/databinded-text/databinded-text.component';
|
||||
import { TimeAgoPipe } from './pipes/time-ago.pipe';
|
||||
import { StreamStatusesComponent } from './components/stream/stream-statuses/stream-statuses.component';
|
||||
import { StreamEditionComponent } from './components/stream/stream-edition/stream-edition.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "", redirectTo: "home", pathMatch: "full" },
|
||||
|
@ -76,9 +79,11 @@ const routes: Routes = [
|
|||
StreamOverlayComponent,
|
||||
DatabindedTextComponent,
|
||||
TimeAgoPipe,
|
||||
StreamStatusesComponent
|
||||
StreamStatusesComponent,
|
||||
StreamEditionComponent
|
||||
],
|
||||
imports: [
|
||||
FontAwesomeModule,
|
||||
BrowserModule,
|
||||
HttpModule,
|
||||
HttpClientModule,
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
<div class="panel">
|
||||
<h3 class="panel__title">Manage Account</h3>
|
||||
<h3 class="panel__title">Manage Account</h3>
|
||||
|
||||
<div class="account-editor__display-avatar">
|
||||
<img class="account-editor__avatar" src="{{account.avatar}}" title="{{ account.info.id }} " />
|
||||
</div>
|
||||
<div class="account-editor__display-avatar">
|
||||
<img class="account-editor__avatar" src="{{account.avatar}}" title="{{ account.info.id }} " />
|
||||
</div>
|
||||
|
||||
<h4 class="add-column__label">add column:</h4>
|
||||
<h4 class="account__label">add column:</h4>
|
||||
|
||||
<a class="add-column__link" href *ngFor="let stream of availableStreams" (click)="addStream(stream)">
|
||||
{{ stream.name }}
|
||||
</a>
|
||||
<!-- <a class="add-column__link" href>
|
||||
<a class="account__link account__blue" href *ngFor="let stream of availableStreams" (click)="addStream(stream)">
|
||||
{{ stream.name }}
|
||||
</a>
|
||||
<!-- <a class="add-column__link" href>
|
||||
Global Timeline
|
||||
</a>
|
||||
<a class="add-column__link" href>
|
||||
|
@ -20,4 +20,9 @@
|
|||
Lists, Favs, Activitires, etc
|
||||
</a> -->
|
||||
|
||||
|
||||
<h4 class="account__label account__margin-top">remove account from sengi:</h4>
|
||||
<a class="account__link account__red" href (click)="removeAccount()">
|
||||
Delete
|
||||
</a>
|
||||
</div>
|
|
@ -20,25 +20,48 @@
|
|||
}
|
||||
}
|
||||
|
||||
.add-column {
|
||||
.account {
|
||||
&__label {
|
||||
// text-decoration: underline;
|
||||
font-size: $small-font-size;
|
||||
margin-left: 5px;
|
||||
color: $font-color-secondary;
|
||||
}
|
||||
&__margin-top {
|
||||
margin-top: 25px;
|
||||
}
|
||||
&__link {
|
||||
text-decoration: none;
|
||||
display: block; // width: calc(100% - 20px);
|
||||
width: 100%; // height: 30px;
|
||||
padding: 5px 10px; // border: solid 1px black;
|
||||
background-color: $color-primary;
|
||||
color: #fff;
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
&__mid-link {
|
||||
text-decoration: none;
|
||||
display: block; // width: calc(100% - 20px);
|
||||
width: 45%; // height: 30px;
|
||||
padding: 5px 10px; // border: solid 1px black;
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
&__blue {
|
||||
background-color: $color-primary;
|
||||
color: #fff;
|
||||
&:hover {
|
||||
background-color: lighten($color-primary, 15);
|
||||
}
|
||||
}
|
||||
|
||||
&__red {
|
||||
$red-button-color: rgb(65, 3, 3);
|
||||
background-color: $red-button-color;
|
||||
color: #fff;
|
||||
&:hover {
|
||||
background-color: lighten($red-button-color, 15);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +1,43 @@
|
|||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { StreamElement, StreamTypeEnum, AddStream } from '../../../states/streams.state';
|
||||
import { StreamElement, StreamTypeEnum, AddStream, RemoveAllStreams } from '../../../states/streams.state';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { AccountsStateModel, AccountInfo } from '../../../states/accounts.state';
|
||||
import { AccountsStateModel, AccountInfo, RemoveAccount } from '../../../states/accounts.state';
|
||||
import { AccountWrapper } from '../../../models/account.models';
|
||||
import { NavigationService } from '../../../services/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-manage-account',
|
||||
templateUrl: './manage-account.component.html',
|
||||
styleUrls: ['./manage-account.component.scss']
|
||||
selector: 'app-manage-account',
|
||||
templateUrl: './manage-account.component.html',
|
||||
styleUrls: ['./manage-account.component.scss']
|
||||
})
|
||||
export class ManageAccountComponent implements OnInit {
|
||||
@Input() account: AccountWrapper;
|
||||
@Input() account: AccountWrapper;
|
||||
|
||||
availableStreams: StreamElement[] = [];
|
||||
availableStreams: StreamElement[] = [];
|
||||
|
||||
constructor(private readonly store: Store) { }
|
||||
constructor(
|
||||
private readonly store: Store,
|
||||
private readonly navigationService: NavigationService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.availableStreams.length = 0;
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.global, 'Global Timeline', this.account.info.id, null, null));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.local, 'Local Timeline', this.account.info.id, null, null));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.personnal, 'Personnal Timeline', this.account.info.id, null, null));
|
||||
}
|
||||
|
||||
addStream(stream: StreamElement): boolean {
|
||||
if (stream) {
|
||||
this.store.dispatch([new AddStream(stream)]);
|
||||
ngOnInit() {
|
||||
const instance = this.account.info.instance;
|
||||
this.availableStreams.length = 0;
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.global, 'Federated Timeline', this.account.info.id, null, null, `federate@${instance}`));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.local, 'Local Timeline', this.account.info.id, null, null, `local@${instance}`));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.personnal, 'Home', this.account.info.id, null, null, `home@${instance}`));
|
||||
}
|
||||
|
||||
addStream(stream: StreamElement): boolean {
|
||||
if (stream) {
|
||||
this.store.dispatch([new AddStream(stream)]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
removeAccount(): boolean {
|
||||
const accountId = this.account.info.id;
|
||||
this.store.dispatch([new RemoveAllStreams(accountId), new RemoveAccount(accountId)]);
|
||||
this.navigationService.closePanel();
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
|||
ngOnInit() {
|
||||
this.accounts$.subscribe((accounts: AccountInfo[]) => {
|
||||
if (accounts) {
|
||||
|
||||
//Update and Add
|
||||
for (let acc of accounts) {
|
||||
const previousAcc = this.accounts.find(x => x.info.id === acc.id)
|
||||
if (previousAcc) {
|
||||
|
@ -41,7 +41,6 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
|||
} else {
|
||||
const accWrapper = new AccountWrapper();
|
||||
accWrapper.info = acc;
|
||||
|
||||
this.accounts.push(accWrapper);
|
||||
|
||||
this.mastodonService.retrieveAccountDetails(acc)
|
||||
|
@ -49,10 +48,12 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
|||
accWrapper.avatar = result.avatar;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: see when deleted
|
||||
|
||||
|
||||
//Delete
|
||||
const deletedAccounts = this.accounts.filter(x => accounts.findIndex(y => y.id === x.info.id) === -1);
|
||||
for(let delAcc of deletedAccounts){
|
||||
this.accounts = this.accounts.filter(x => x.info.id !== delAcc.info.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -33,7 +33,7 @@ export class HashtagComponent implements OnInit {
|
|||
event.stopPropagation();
|
||||
|
||||
const hashtag = this.hashtagElement.tag;
|
||||
const newStream = new StreamElement(StreamTypeEnum.tag, `#${hashtag}`, this.hashtagElement.accountId, hashtag, null);
|
||||
const newStream = new StreamElement(StreamTypeEnum.tag, `${hashtag}`, this.hashtagElement.accountId, hashtag, null, this.hashtagElement.displayableFullName);
|
||||
this.store.dispatch([new AddStream(newStream)]);
|
||||
|
||||
return false;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="reblog" *ngIf="reblog">
|
||||
<a class="reblog__profile-link" href (click)="openAccount(status.account)">{{ status.account.display_name }} <img *ngIf="reblog" class="reblog__avatar"
|
||||
src="{{ status.account.avatar }}" /></a> boosted
|
||||
<a class="reblog__profile-link" href (click)="openAccount(status.account)">{{ status.account.display_name }} <img
|
||||
*ngIf="reblog" class="reblog__avatar" src="{{ status.account.avatar }}" /></a> boosted
|
||||
</div>
|
||||
<div class="status">
|
||||
|
||||
|
@ -12,11 +12,15 @@
|
|||
class="status__name--username">{{displayedStatus.account.acct}}</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="status__created-at" title="{{ displayedStatus.created_at | date: 'full' }}">{{
|
||||
status.created_at | timeAgo | async }}</div>
|
||||
<div class="status__created-at" title="{{ displayedStatus.created_at | date: 'full' }}">
|
||||
<a class="status__created-at--link" href="{{ displayedStatus.url }}" target="_blank">
|
||||
{{ status.created_at | timeAgo | async }}
|
||||
</a>
|
||||
</div>
|
||||
<!-- <div #content class="status__content" innerHTML="{{displayedStatus.content}}"></div> -->
|
||||
|
||||
<app-databinded-text class="status__content" [text]="displayedStatus.content" (accountSelected)="accountSelected($event)" (hashtagSelected)="hashtagSelected($event)" (textSelected)="textSelected()"></app-databinded-text>
|
||||
<app-databinded-text class="status__content" [text]="displayedStatus.content" (accountSelected)="accountSelected($event)"
|
||||
(hashtagSelected)="hashtagSelected($event)" (textSelected)="textSelected()"></app-databinded-text>
|
||||
|
||||
|
||||
<app-attachements *ngIf="hasAttachments" class="attachments" [attachments]="displayedStatus.media_attachments"></app-attachements>
|
||||
|
|
|
@ -83,11 +83,19 @@
|
|||
// margin: 0 !important;
|
||||
// font-size: 0.85em;
|
||||
// }
|
||||
&__created-at {
|
||||
color: $status-secondary-color;
|
||||
&__created-at {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 5px;
|
||||
|
||||
&--link {
|
||||
color: $status-secondary-color;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: lighten($status-secondary-color, 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<div class="stream-edition">
|
||||
<button (click)="moveLeft()" class="stream-edition__button" title="move left"><fa-icon [icon]="faChevronLeft"></fa-icon></button>
|
||||
<button (click)="moveRight()" class="stream-edition__button" title="move right"><fa-icon [icon]="faChevronRight"></fa-icon></button>
|
||||
<button (click)="delete()" class="stream-edition__button stream-edition__button--delete" title="remove column"><fa-icon [icon]="faTimes"></fa-icon></button>
|
||||
</div>
|
|
@ -0,0 +1,21 @@
|
|||
@import "variables";
|
||||
@import "mixins";
|
||||
|
||||
.stream-edition {
|
||||
width: 100%;
|
||||
// min-height: 50px;
|
||||
background-color: #222736;
|
||||
&__button {
|
||||
@include clearButton;
|
||||
padding: 5px 10px 5px 10px;
|
||||
margin: 3px 0;
|
||||
&--delete{
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: darken($font-color-primary, 20);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StreamEditionComponent } from './stream-edition.component';
|
||||
|
||||
xdescribe('StreamEditionComponent', () => {
|
||||
let component: StreamEditionComponent;
|
||||
let fixture: ComponentFixture<StreamEditionComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ StreamEditionComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StreamEditionComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { faChevronLeft, faChevronRight, faTimes } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import { StreamElement, RemoveStream, MoveStreamUp, MoveStreamDown } from '../../../states/streams.state';
|
||||
|
||||
@Component({
|
||||
selector: 'app-stream-edition',
|
||||
templateUrl: './stream-edition.component.html',
|
||||
styleUrls: ['./stream-edition.component.scss']
|
||||
})
|
||||
export class StreamEditionComponent implements OnInit {
|
||||
faChevronLeft = faChevronLeft;
|
||||
faChevronRight = faChevronRight;
|
||||
faTimes = faTimes;
|
||||
|
||||
@Input() streamElement: StreamElement;
|
||||
|
||||
constructor(private readonly store: Store) { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
moveLeft(): boolean {
|
||||
this.store.dispatch([new MoveStreamUp(this.streamElement.id)]);
|
||||
return false;
|
||||
}
|
||||
|
||||
moveRight(): boolean {
|
||||
this.store.dispatch([new MoveStreamDown(this.streamElement.id)]);
|
||||
return false;
|
||||
}
|
||||
|
||||
delete(): boolean {
|
||||
this.store.dispatch([new RemoveStream(this.streamElement.id)]);
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -116,7 +116,7 @@ export class StreamOverlayComponent implements OnInit {
|
|||
}
|
||||
|
||||
const selectedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
const hashTagElement = new StreamElement(StreamTypeEnum.tag, hashtag, selectedAccount.id, hashtag, null);
|
||||
const hashTagElement = new StreamElement(StreamTypeEnum.tag, hashtag, selectedAccount.id, hashtag, null, `#${hashtag}@${selectedAccount.instance}`);
|
||||
const newElement = new OverlayBrowsing(hashTagElement, null, null);
|
||||
this.loadElement(newElement);
|
||||
this.canGoForward = false;
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
<div class="stream-column">
|
||||
|
||||
<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 class="stream-column__stream-header">
|
||||
<a href title="return to top" (click)="goToTop()">
|
||||
<h1>{{ streamElement.name.toUpperCase() }}</h1>
|
||||
<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>
|
||||
<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>
|
||||
</a>
|
||||
</div>
|
||||
<app-stream-statuses class="stream-statuses" [streamElement]="streamElement" [goToTop]="goToTopSubject.asObservable()" (browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)"></app-stream-statuses>
|
||||
|
||||
<app-stream-edition class="stream-edition" *ngIf="editionPanelIsOpen"
|
||||
[streamElement]="streamElement"></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 class="stream-toots flexcroll" #statusstream (scroll)="onScroll()">
|
||||
<div class="stream-toots__status" *ngFor="let statusWrapper of statuses">
|
||||
<app-status [statusWrapper]="statusWrapper" (browseAccount)="browseAccount($event)" (browseHashtag)="browseHashtag($event)"></app-status>
|
||||
|
|
|
@ -1,30 +1,63 @@
|
|||
@import "variables";
|
||||
@import "commons";
|
||||
$stream-header-height: 40px;
|
||||
.stream-edition {
|
||||
width: $stream-column-width;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.stream-column {
|
||||
position: relative;
|
||||
|
||||
width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
background-color: $column-color;
|
||||
margin: 0 0 0 $stream-column-separator;
|
||||
&__stream-header {
|
||||
border-bottom: 1px solid #222736;
|
||||
}
|
||||
&__open-menu {
|
||||
float: right;
|
||||
display: block;
|
||||
width: $stream-header-height - 10px;
|
||||
height: $stream-header-height - 10px;
|
||||
margin: 5px;
|
||||
&:hover &--icon {
|
||||
color: darken(whitesmoke, 30);
|
||||
}
|
||||
&--icon {
|
||||
color: whitesmoke; // float: left;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
&__stream-selector {
|
||||
display: block;
|
||||
width: calc(100%);
|
||||
height: 30px;
|
||||
height: $stream-header-height;
|
||||
background-color: $column-header-background-color;
|
||||
border-bottom: 1px solid black;
|
||||
& h1 {
|
||||
text-decoration: none; // &:hover {
|
||||
// }
|
||||
&--icon {
|
||||
color: whitesmoke;
|
||||
float: left;
|
||||
position: relative;
|
||||
left: 11px;
|
||||
top: 9px;
|
||||
}
|
||||
&--title {
|
||||
color: whitesmoke;
|
||||
font-size: 0.8em;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 8px 0 0 10px;
|
||||
font-weight: normal; // margin: 0 0 0 25px;
|
||||
padding: 14px 0 0 35px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stream-statuses {
|
||||
display: block;
|
||||
height: calc(100% - 30px);
|
||||
height: calc(100% - #{$stream-header-height});
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
|
@ -37,11 +70,9 @@
|
|||
// border-width: 0 0 1px 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
.stream-overlay {
|
||||
position: absolute;
|
||||
|
||||
z-index: 50;
|
||||
z-index: 100;
|
||||
width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
import { Component, OnInit, Input, ElementRef, ViewChild, HostListener } from "@angular/core";
|
||||
import { Subject } from "rxjs";
|
||||
import { faHome, faGlobe, faUser, faHashtag, faListUl, faBars, IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import { StreamElement } from "../../states/streams.state";
|
||||
import { StreamElement, StreamTypeEnum } from "../../states/streams.state";
|
||||
import { Status } from "../../services/models/mastodon.interfaces";
|
||||
import { AccountInfo } from "../../states/accounts.state";
|
||||
|
||||
|
@ -11,6 +12,9 @@ import { AccountInfo } from "../../states/accounts.state";
|
|||
styleUrls: ["./stream.component.scss"]
|
||||
})
|
||||
export class StreamComponent implements OnInit {
|
||||
columnFaIcon: IconDefinition;
|
||||
menuFaIcon = faBars;
|
||||
|
||||
overlayActive: boolean;
|
||||
overlayAccountToBrowse: string;
|
||||
overlayHashtagToBrowse: string;
|
||||
|
@ -18,7 +22,34 @@ export class StreamComponent implements OnInit {
|
|||
|
||||
goToTopSubject: Subject<void> = new Subject<void>();
|
||||
|
||||
@Input() streamElement: StreamElement;
|
||||
private _streamElement: StreamElement;
|
||||
|
||||
@Input('streamElement')
|
||||
set streamElement(stream: StreamElement) {
|
||||
switch (stream.type) {
|
||||
case StreamTypeEnum.personnal:
|
||||
this.columnFaIcon = faHome;
|
||||
break;
|
||||
case StreamTypeEnum.global:
|
||||
this.columnFaIcon = faGlobe;
|
||||
break;
|
||||
case StreamTypeEnum.local:
|
||||
this.columnFaIcon = faUser;
|
||||
break;
|
||||
case StreamTypeEnum.tag:
|
||||
this.columnFaIcon = faHashtag;
|
||||
break;
|
||||
case StreamTypeEnum.list:
|
||||
this.columnFaIcon = faListUl;
|
||||
break;
|
||||
}
|
||||
|
||||
this._streamElement = stream;
|
||||
}
|
||||
get streamElement(): StreamElement {
|
||||
return this._streamElement;
|
||||
}
|
||||
|
||||
|
||||
constructor() { }
|
||||
|
||||
|
@ -57,6 +88,13 @@ export class StreamComponent implements OnInit {
|
|||
this.overlayThreadToBrowse = null;
|
||||
this.overlayActive = false;
|
||||
}
|
||||
|
||||
editionPanelIsOpen: boolean;
|
||||
openEditionMenu(): boolean {
|
||||
console.log('opened menu');
|
||||
this.editionPanelIsOpen = !this.editionPanelIsOpen;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class StatusWrapper {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="streams-selection-footer">
|
||||
<a class="stream-selection" *ngFor="let str of streams; let i=index" href (click)="onColumnSelection(i)" >
|
||||
<a class="stream-selection" *ngFor="let str of streams; let i=index" href (click)="onColumnSelection(i)" title="open {{str.displayableFullName}}">
|
||||
<span class="stream-selection__column-reprensentation"></span>
|
||||
</a>
|
||||
</div>
|
|
@ -33,7 +33,7 @@ export class StreamsMainDisplayComponent implements OnInit, OnDestroy {
|
|||
private focusOnColumn(columnIndex: number): void {
|
||||
if (columnIndex > -1) {
|
||||
setTimeout(() => {
|
||||
this.streamsElementRef.toArray()[columnIndex].nativeElement.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'start' });
|
||||
this.streamsElementRef.toArray()[columnIndex].nativeElement.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@ export class SelectAccount {
|
|||
constructor(public account: AccountInfo, public multiselection: boolean = false) {}
|
||||
}
|
||||
|
||||
export class RemoveAccount {
|
||||
static readonly type = '[Accounts] Remove account';
|
||||
constructor(public accountId: string) {}
|
||||
}
|
||||
|
||||
export interface AccountsStateModel {
|
||||
accounts: AccountInfo[];
|
||||
}
|
||||
|
@ -51,6 +56,15 @@ export class AccountsState {
|
|||
accounts: copyAccounts
|
||||
});
|
||||
}
|
||||
|
||||
@Action(RemoveAccount)
|
||||
RemoveAccount(ctx: StateContext<AccountsStateModel>, action: RemoveAccount){
|
||||
const state = ctx.getState();
|
||||
const filteredAccounts = state.accounts.filter(x => x.id !== action.accountId);
|
||||
ctx.patchState({
|
||||
accounts: filteredAccounts
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class AccountInfo {
|
||||
|
|
|
@ -5,6 +5,26 @@ export class AddStream {
|
|||
constructor(public stream: StreamElement) {}
|
||||
}
|
||||
|
||||
export class RemoveAllStreams {
|
||||
static readonly type = '[Streams] Remove all streams';
|
||||
constructor(public accountId :string) {}
|
||||
}
|
||||
|
||||
export class RemoveStream {
|
||||
static readonly type = '[Streams] Remove stream';
|
||||
constructor(public streamId :string) {}
|
||||
}
|
||||
|
||||
export class MoveStreamUp {
|
||||
static readonly type = '[Streams] Move stream up';
|
||||
constructor(public streamId :string) {}
|
||||
}
|
||||
|
||||
export class MoveStreamDown {
|
||||
static readonly type = '[Streams] Move stream down';
|
||||
constructor(public streamId :string) {}
|
||||
}
|
||||
|
||||
export interface StreamsStateModel {
|
||||
streams: StreamElement[];
|
||||
}
|
||||
|
@ -23,15 +43,63 @@ export class StreamsState {
|
|||
streams: [...state.streams, action.stream]
|
||||
});
|
||||
}
|
||||
@Action(RemoveAllStreams)
|
||||
RemoveAllStreams(ctx: StateContext<StreamsStateModel>, action: RemoveAllStreams){
|
||||
const state = ctx.getState();
|
||||
const filteredStreams = state.streams.filter(x => x.accountId !== action.accountId);
|
||||
ctx.patchState({
|
||||
streams: [...filteredStreams]
|
||||
});
|
||||
}
|
||||
@Action(RemoveStream)
|
||||
RemoveStream(ctx: StateContext<StreamsStateModel>, action: RemoveStream){
|
||||
const state = ctx.getState();
|
||||
const filteredStreams = state.streams.filter(x => x.id !== action.streamId);
|
||||
ctx.patchState({
|
||||
streams: [...filteredStreams]
|
||||
});
|
||||
}
|
||||
@Action(MoveStreamUp)
|
||||
MoveStreamUp(ctx: StateContext<StreamsStateModel>, action: MoveStreamUp){
|
||||
const state = ctx.getState();
|
||||
const sourceIndex = state.streams.findIndex(x => x.id === action.streamId);
|
||||
if(sourceIndex === 0) return;
|
||||
|
||||
let streamsCopy = [...state.streams];
|
||||
streamsCopy[sourceIndex - 1] = state.streams[sourceIndex];
|
||||
streamsCopy[sourceIndex] = state.streams[sourceIndex - 1];
|
||||
|
||||
ctx.patchState({
|
||||
streams: streamsCopy
|
||||
});
|
||||
}
|
||||
@Action(MoveStreamDown)
|
||||
MoveStreamDown(ctx: StateContext<StreamsStateModel>, action: MoveStreamDown){
|
||||
const state = ctx.getState();
|
||||
const sourceIndex = state.streams.findIndex(x => x.id === action.streamId);
|
||||
if(sourceIndex === state.streams.length - 1) return;
|
||||
|
||||
let streamsCopy = [...state.streams];
|
||||
streamsCopy[sourceIndex + 1] = state.streams[sourceIndex];
|
||||
streamsCopy[sourceIndex] = state.streams[sourceIndex + 1];
|
||||
|
||||
ctx.patchState({
|
||||
streams: streamsCopy
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class StreamElement {
|
||||
public id: string;
|
||||
|
||||
constructor(
|
||||
public type: StreamTypeEnum,
|
||||
public name: string,
|
||||
public accountId: string,
|
||||
public tag: string,
|
||||
public list: string) {
|
||||
public list: string,
|
||||
public displayableFullName: string) {
|
||||
this.id = `${type}-${name}-${accountId}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,4 +4,14 @@
|
|||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin clearButton {
|
||||
background: none;
|
||||
color: inherit;
|
||||
border: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
outline: inherit;
|
||||
}
|
|
@ -6,7 +6,7 @@ $color-primary: #141824;
|
|||
$color-secondary: #090b10;
|
||||
|
||||
$column-color: #0f111a;
|
||||
$column-header-background-color: black;
|
||||
$column-header-background-color: #0c0c10;
|
||||
|
||||
|
||||
|
||||
|
@ -32,6 +32,7 @@ $stream-selector-height: 30px;
|
|||
$stream-column-separator: 7px;
|
||||
$stream-column-width: 320px;
|
||||
$avatar-column-space: 70px;
|
||||
|
||||
//Bootstrap cuistomization
|
||||
$enable-rounded: false;
|
||||
|
||||
|
|
Loading…
Reference in New Issue