Merge pull request #3 from NicolasConstant/topic-start-column-handling
Topic start column handling
This commit is contained in:
commit
dd08f5025c
|
@ -26,6 +26,7 @@
|
|||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": [
|
||||
"./src/sass",
|
||||
"./node_modules/bootstrap/scss"
|
||||
]
|
||||
},
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
</app-streams-main-display>-->
|
||||
|
||||
<div id="display-zone">
|
||||
<app-floating-column id="floating-column" *ngIf="floatingColumnActive">
|
||||
|
||||
</app-floating-column>
|
||||
<router-outlet>
|
||||
</router-outlet>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
app-left-side-bar {
|
||||
|
||||
}
|
||||
|
||||
#display-zone {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -13,6 +9,14 @@ app-left-side-bar {
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#floating-column {
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
|
||||
app-streams-selection-footer {
|
||||
position: absolute;
|
||||
height: 30px;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { ElectronService } from 'ngx-electron';
|
||||
import { NavigationService } from './services/navigation.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { AccountWrapper } from './models/account.models';
|
||||
|
||||
|
||||
@Component({
|
||||
|
@ -7,15 +10,29 @@ import { ElectronService } from 'ngx-electron';
|
|||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent {
|
||||
export class AppComponent implements OnInit, OnDestroy{
|
||||
|
||||
title = 'app';
|
||||
|
||||
constructor(private _electronService: ElectronService) {
|
||||
private floatingColumnActive: boolean;
|
||||
private columnEditorSub: Subscription;
|
||||
|
||||
constructor(private readonly navigationService: NavigationService) {
|
||||
|
||||
}
|
||||
|
||||
launchWindow(){
|
||||
this._electronService.shell.openExternal('http://google.com');
|
||||
|
||||
ngOnInit(): void {
|
||||
this.columnEditorSub = this.navigationService.openColumnEditorSubject.subscribe((acc: AccountWrapper) => {
|
||||
if(acc) {
|
||||
this.floatingColumnActive = true;
|
||||
} else {
|
||||
this.floatingColumnActive = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.columnEditorSub.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,11 +19,15 @@ import { TootComponent } from "./components/toot/toot.component";
|
|||
import { RegisterNewAccountComponent } from "./pages/register-new-account/register-new-account.component";
|
||||
import { AuthService } from "./services/auth.service";
|
||||
import { AccountsService } from "./services/accounts.service";
|
||||
import { StreamsService } from "./services/streams.service";
|
||||
import { StreamingService } from "./services/streaming.service";
|
||||
import { RegisteredAppsState } from "./states/registered-apps.state";
|
||||
import { AccountsState } from "./states/accounts.state";
|
||||
import { AccountIconComponent } from './components/left-side-bar/presentation/account-icon/account-icon.component';
|
||||
import { NavigationService } from "./services/navigation.service";
|
||||
import { FloatingColumnComponent } from './components/floating-column/floating-column.component';
|
||||
import { ColumnsEditorComponent } from './components/floating-column/columns-editor/columns-editor.component';
|
||||
import { MessageEditorComponent } from './components/floating-column/message-editor/message-editor.component';
|
||||
import { StreamsState } from "./states/streams.state";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "", redirectTo: "home", pathMatch: "full" },
|
||||
|
@ -41,7 +45,10 @@ const routes: Routes = [
|
|||
StreamsSelectionFooterComponent,
|
||||
TootComponent,
|
||||
RegisterNewAccountComponent,
|
||||
AccountIconComponent
|
||||
AccountIconComponent,
|
||||
FloatingColumnComponent,
|
||||
ColumnsEditorComponent,
|
||||
MessageEditorComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -53,11 +60,12 @@ const routes: Routes = [
|
|||
|
||||
NgxsModule.forRoot([
|
||||
RegisteredAppsState,
|
||||
AccountsState
|
||||
AccountsState,
|
||||
StreamsState
|
||||
]),
|
||||
NgxsStoragePluginModule.forRoot()
|
||||
],
|
||||
providers: [AuthService, AccountsService, StreamsService, StreamingService, { provide: APP_INITIALIZER, useFactory: settingsServiceFactory, deps: [AccountsService], multi: true }],
|
||||
providers: [AuthService, NavigationService, AccountsService, StreamingService, { provide: APP_INITIALIZER, useFactory: settingsServiceFactory, deps: [AccountsService], multi: true }],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<div class="account-editor">
|
||||
<h3 class="account-editor__title">Manage Account</h3>
|
||||
|
||||
<div class="account-editor__display-avatar">
|
||||
<img class="account-editor__avatar" src="{{account.avatar}}" title="{{ account.username }} " />
|
||||
</div>
|
||||
|
||||
<h4 class="add-column__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>
|
||||
Global Timeline
|
||||
</a>
|
||||
<a class="add-column__link" href>
|
||||
Personnal Timeline
|
||||
</a>
|
||||
<a class="add-column__link" href>
|
||||
Lists, Favs, Activitires, etc
|
||||
</a> -->
|
||||
|
||||
</div>
|
|
@ -0,0 +1,43 @@
|
|||
@import "variables";
|
||||
.account-editor {
|
||||
padding: 10px 10px 0 7px;
|
||||
font-size: $small-font-size;
|
||||
&__title {
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
margin: 6px 0 12px 0;
|
||||
}
|
||||
&__display-avatar {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
&__avatar {
|
||||
// display: block;
|
||||
width: 75px;
|
||||
border-radius: 50px;
|
||||
transform: translateX(15px); // margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.add-column {
|
||||
&__label {
|
||||
// text-decoration: underline;
|
||||
font-size: $small-font-size;
|
||||
margin-left: 5px;
|
||||
color: $font-color-secondary;
|
||||
}
|
||||
&__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;
|
||||
}
|
||||
&:hover {
|
||||
background-color: lighten($color-primary, 15);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ColumnsEditorComponent } from './columns-editor.component';
|
||||
|
||||
describe('ColumnsEditorComponent', () => {
|
||||
let component: ColumnsEditorComponent;
|
||||
let fixture: ComponentFixture<ColumnsEditorComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ColumnsEditorComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ColumnsEditorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { StreamElement, StreamTypeEnum, AddStream } from '../../../states/streams.state';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { AccountsStateModel, AccountInfo } from '../../../states/accounts.state';
|
||||
import { AccountWrapper } from '../../../models/account.models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-columns-editor',
|
||||
templateUrl: './columns-editor.component.html',
|
||||
styleUrls: ['./columns-editor.component.scss']
|
||||
})
|
||||
export class ColumnsEditorComponent implements OnInit {
|
||||
@Input() account: AccountWrapper;
|
||||
|
||||
availableStreams: StreamElement[] = [];
|
||||
|
||||
constructor(private readonly store: Store) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.availableStreams.length = 0;
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.global, 'Global Timeline', this.account.username));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.local, 'Local Timeline', this.account.username));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.personnal, 'Personnal Timeline', this.account.username));
|
||||
}
|
||||
|
||||
addStream(stream: StreamElement): boolean {
|
||||
if (stream) {
|
||||
this.store.dispatch([new AddStream(stream)]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<div class="floating-column">
|
||||
<div class="floating-column__header">
|
||||
<a class="close-button" href (click)="closePanel()" title="close">x</a>
|
||||
</div>
|
||||
|
||||
<app-columns-editor *ngIf="columnEditorIsOpen" [account]="userAccountUsed"></app-columns-editor>
|
||||
<app-message-editor *ngIf="messageEditorIsOpen"></app-message-editor>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,46 @@
|
|||
@import "variables";
|
||||
@import "mixins";
|
||||
|
||||
.floating-column {
|
||||
width: calc(100%);
|
||||
max-width: 330px;
|
||||
|
||||
background-color: $color-secondary;
|
||||
overflow: hidden;
|
||||
z-index: 99;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: $stream-selector-height;
|
||||
padding: 0;
|
||||
|
||||
&__header {
|
||||
|
||||
// @include clearfix;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.close-button {
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FloatingColumnComponent } from './floating-column.component';
|
||||
|
||||
describe('FloatingColumnComponent', () => {
|
||||
let component: FloatingColumnComponent;
|
||||
let fixture: ComponentFixture<FloatingColumnComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FloatingColumnComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FloatingColumnComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { NavigationService } from '../../services/navigation.service';
|
||||
import { AccountWrapper } from '../../models/account.models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-floating-column',
|
||||
templateUrl: './floating-column.component.html',
|
||||
styleUrls: ['./floating-column.component.scss']
|
||||
})
|
||||
export class FloatingColumnComponent implements OnInit {
|
||||
userAccountUsed: AccountWrapper;
|
||||
columnEditorIsOpen: boolean;
|
||||
messageEditorIsOpen: boolean;
|
||||
|
||||
constructor(private readonly navigationService: NavigationService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.navigationService.openColumnEditorSubject.subscribe((acc: AccountWrapper) => {
|
||||
this.userAccountUsed = acc;
|
||||
if(this.userAccountUsed) {
|
||||
this.columnEditorIsOpen = true;
|
||||
} else {
|
||||
this.columnEditorIsOpen = false;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
closePanel(): boolean {
|
||||
this.navigationService.closeColumnEditor();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<p>
|
||||
message-editor works!
|
||||
</p>
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MessageEditorComponent } from './message-editor.component';
|
||||
|
||||
describe('MessageEditorComponent', () => {
|
||||
let component: MessageEditorComponent;
|
||||
let fixture: ComponentFixture<MessageEditorComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ MessageEditorComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MessageEditorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-message-editor',
|
||||
templateUrl: './message-editor.component.html',
|
||||
styleUrls: ['./message-editor.component.scss']
|
||||
})
|
||||
export class MessageEditorComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,22 +1,16 @@
|
|||
<div id="mam-left-bar">
|
||||
<div id="mam-create-toot">
|
||||
<a href title="write toot!" (click)="createNewToot()">Toot!</a>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let account of accounts" >
|
||||
<app-account-icon [account]="account" ></app-account-icon>
|
||||
|
||||
<!-- <a href title="{{ account.username }}" (click)="toogleAccount(account.id)"><img src="{{ account.avatar }}" /></a> -->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="mam-account-add">
|
||||
<a href title="add new account" [routerLink]="['/register']">+</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="left-bar" >
|
||||
<div id="create-toot">
|
||||
<a class="create-toot__link left-bar-link" href title="write toot!" (click)="createNewToot()">Toot!</a>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let account of accounts">
|
||||
<app-account-icon [account]="account" (toogleAccountNotify)="onToogleAccountNotify($event)" (openMenuNotify)="onOpenMenuNotify($event)">
|
||||
</app-account-icon>
|
||||
|
||||
<!-- <a href title="{{ account.username }}" (click)="toogleAccount(account.id)"><img src="{{ account.avatar }}" /></a> -->
|
||||
</div>
|
||||
|
||||
<div class="add-account">
|
||||
<a class="add-account__link left-bar-link" href title="add new account" [routerLink]="['/register']">+</a>
|
||||
</div>
|
||||
</div>
|
|
@ -1,55 +1,34 @@
|
|||
#mam-left-bar {
|
||||
width: 50px;
|
||||
height: calc(100%);
|
||||
background: green;
|
||||
background: #090b10;
|
||||
|
||||
/*outline: 1px dotted red;*/
|
||||
@import "variables";
|
||||
.left-bar {
|
||||
width: 50px;
|
||||
height: calc(100%);
|
||||
background: $color-secondary;
|
||||
}
|
||||
|
||||
#mam-create-toot {
|
||||
width: 50px;
|
||||
|
||||
/* background-color: black; */
|
||||
.create-toot {
|
||||
width: 50px;
|
||||
&__link {
|
||||
font-size: 0.8em;
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#mam-create-toot a {
|
||||
font-size: 0.8em;
|
||||
/* color: white; */
|
||||
.add-account {
|
||||
width: 50px;
|
||||
height: 30px;
|
||||
padding-top: 7px;
|
||||
&__link {
|
||||
font-size: 2em;
|
||||
height: 10px;
|
||||
margin: 0 15px;
|
||||
line-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.left-bar-link {
|
||||
color: $font-link-primary;
|
||||
text-decoration: none;
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
|
||||
|
||||
.mam-account-selector {
|
||||
width: 50px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.mam-account-selector a {
|
||||
margin-left: 4px;
|
||||
/*margin-top: 4px;*/
|
||||
}
|
||||
|
||||
.mam-account-selector img {
|
||||
width: 40px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#mam-account-add {
|
||||
width: 50px;
|
||||
/*height: 50px;*/
|
||||
|
||||
/* background-color: black; */
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 2em;
|
||||
color: #595c67;
|
||||
text-decoration: none;
|
||||
margin: 10px 0 0 15px;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #8f93a2;
|
||||
&:hover {
|
||||
color: $font-link-primary-hover;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import { Account } from "../../services/models/mastodon.interfaces";
|
|||
import { AccountWrapper } from "../../models/account.models";
|
||||
import { AccountsService } from "../../services/accounts.service";
|
||||
import { AccountsStateModel, AccountInfo } from "../../states/accounts.state";
|
||||
import { NavigationService } from "../../services/navigation.service";
|
||||
|
||||
|
||||
@Component({
|
||||
|
@ -17,9 +18,11 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
|||
accounts: AccountWrapper[] = [];
|
||||
accounts$: Observable<AccountInfo[]>;
|
||||
|
||||
private loadedAccounts: { [index: string]: AccountInfo } = {};
|
||||
private sub: Subscription;
|
||||
|
||||
constructor(
|
||||
private readonly navigationService: NavigationService,
|
||||
private readonly accountsService: AccountsService,
|
||||
private readonly store: Store) {
|
||||
|
||||
|
@ -29,24 +32,19 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
|||
private currentLoading: number;
|
||||
ngOnInit() {
|
||||
this.accounts$.subscribe((accounts: AccountInfo[]) => {
|
||||
console.warn(' this.accounts$.subscribe(');
|
||||
console.warn(accounts);
|
||||
|
||||
|
||||
if (accounts) {
|
||||
for (let acc of accounts) {
|
||||
this.loadedAccounts = {};
|
||||
this.accounts.length = 0;
|
||||
|
||||
for (let acc of accounts) {
|
||||
const accWrapper = new AccountWrapper();
|
||||
accWrapper.username = `${acc.username}@${acc.instance}`;
|
||||
this.accounts.push(accWrapper);
|
||||
this.loadedAccounts[accWrapper.username] = acc;
|
||||
|
||||
this.accountsService.retrieveAccountDetails(acc)
|
||||
.then((result: Account) => {
|
||||
console.error(result);
|
||||
const accounts = this.accounts.filter(x => result.url.includes(acc.username) && result.url.includes(acc.instance));
|
||||
for (const account of accounts) {
|
||||
account.avatar = result.avatar;
|
||||
}
|
||||
accWrapper.avatar = result.avatar;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -57,8 +55,13 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
|||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
addNewAccount(): boolean {
|
||||
return false;
|
||||
onToogleAccountNotify(acc: AccountWrapper) {
|
||||
console.warn(`onToogleAccountNotify username ${acc.username}`);
|
||||
}
|
||||
|
||||
onOpenMenuNotify(acc: AccountWrapper) {
|
||||
console.warn(`onOpenMenuNotify username ${acc.username}`);
|
||||
this.navigationService.openColumnEditor(acc);
|
||||
}
|
||||
|
||||
createNewToot(): boolean {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<a class="account-icon" href title="{{ account.username }}" (click)="toogleAccount()" (contextmenu)="openMenu()">
|
||||
<img class="account-icon__avatar" src="{{ account.avatar }}" />
|
||||
<a class="account-icon"
|
||||
href title="{{ account.username }}" (click)="toogleAccount()" (contextmenu)="openMenu()">
|
||||
<img class="account-icon__avatar" [class.account-icon__avatar--selected]="isSelected" src="{{ account.avatar }}" />
|
||||
</a>
|
||||
|
|
|
@ -1,15 +1,39 @@
|
|||
.account-icon {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
padding-top: 4px;
|
||||
// padding-top: 4px;
|
||||
// margin-left: 5px;
|
||||
margin: 0 0 5px 5px;
|
||||
|
||||
|
||||
|
||||
|
||||
&__avatar {
|
||||
border-radius: 50%;
|
||||
border-radius: 2px;
|
||||
width: 40px;
|
||||
opacity: .3;
|
||||
transition: all .2s;
|
||||
|
||||
&:hover {
|
||||
filter: alpha(opacity=50);
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
&--selected {
|
||||
// border-radius: 20%;
|
||||
filter: alpha(opacity=100);
|
||||
opacity: 1;
|
||||
|
||||
&:hover {
|
||||
filter: alpha(opacity=100);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// & a {
|
||||
// margin-left: 4px;
|
||||
// /*margin-top: 4px;*/
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { AccountInfo } from '../../../../states/accounts.state';
|
||||
import { AccountsService } from '../../../../services/accounts.service';
|
||||
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
|
||||
import { AccountWrapper } from '../../../../models/account.models';
|
||||
import { Account } from "../../../../services/models/mastodon.interfaces";
|
||||
|
||||
@Component({
|
||||
selector: 'app-account-icon',
|
||||
|
@ -11,6 +8,10 @@ import { Account } from "../../../../services/models/mastodon.interfaces";
|
|||
})
|
||||
export class AccountIconComponent implements OnInit {
|
||||
@Input() account: AccountWrapper;
|
||||
@Output() toogleAccountNotify = new EventEmitter<AccountWrapper>();
|
||||
@Output() openMenuNotify = new EventEmitter<AccountWrapper>();
|
||||
|
||||
isSelected: boolean = false;
|
||||
|
||||
constructor() { }
|
||||
|
||||
|
@ -18,12 +19,13 @@ export class AccountIconComponent implements OnInit {
|
|||
}
|
||||
|
||||
toogleAccount(): boolean {
|
||||
console.warn(`click`);
|
||||
this.toogleAccountNotify.emit(this.account);
|
||||
this.isSelected = !this.isSelected;
|
||||
return false;
|
||||
}
|
||||
|
||||
openMenu(event): boolean {
|
||||
console.warn(`openMenu`);
|
||||
this.openMenuNotify.emit(this.account);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<div id="mam-stream-column">
|
||||
<div id="mam-stream-header">
|
||||
<div class="stream-column">
|
||||
<div class="stream-column__stream-header">
|
||||
<a href title="return to top" (click)="goToTop()"><h1>{{ stream.streamName.toUpperCase() }}</h1></a>
|
||||
</div>
|
||||
<div id="mam-stream-toots" data-simplebar>
|
||||
<div class="stream-toots" data-simplebar>
|
||||
<div *ngFor="let toot of toots">
|
||||
<app-toot [toot]="toot"></app-toot>
|
||||
</div>
|
||||
|
|
|
@ -1,33 +1,31 @@
|
|||
#mam-stream-column {
|
||||
width: 320px; /*320*/
|
||||
@import "variables";
|
||||
.stream-column {
|
||||
width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
|
||||
background-color: #090b10;
|
||||
background-color: #0f111a;
|
||||
margin: 0 0 0 $stream-column-separator;
|
||||
|
||||
}
|
||||
&__stream-header {
|
||||
width: calc(100%);
|
||||
height: 30px;
|
||||
|
||||
#mam-stream-header {
|
||||
width: calc(100%);
|
||||
height: 30px;
|
||||
background-color: black;
|
||||
|
||||
background-color: black;
|
||||
border-bottom: 1px solid black;
|
||||
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
|
||||
#mam-stream-header h1 {
|
||||
color: whitesmoke;
|
||||
font-size: 0.8em;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 8px 0 0 10px;
|
||||
& h1 {
|
||||
color: whitesmoke;
|
||||
font-size: 0.8em;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 8px 0 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#mam-stream-toots {
|
||||
.stream-toots {
|
||||
height: calc(100% - 30px);
|
||||
width: 320px;
|
||||
overflow: auto;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<div id="mam-streams-selection-footer">
|
||||
|
||||
<div class="streams-selection-footer">
|
||||
<a class="stream-selection" *ngFor="let str of streams; let i=index" href (click)="onColumnSelection(i)" >
|
||||
<span class="stream-selection__column-reprensentation"></span>
|
||||
</a>
|
||||
</div>
|
|
@ -1,6 +1,29 @@
|
|||
#mam-streams-selection-footer {
|
||||
width: calc(100%);
|
||||
height: 30px;
|
||||
@import "variables";
|
||||
|
||||
background-color: #090b10;
|
||||
.streams-selection-footer {
|
||||
width: calc(100%);
|
||||
height: $stream-selector-height;
|
||||
text-align: center;
|
||||
|
||||
background-color: $color-secondary;
|
||||
}
|
||||
|
||||
.stream-selection {
|
||||
display: inline-block;
|
||||
width: 9px;
|
||||
padding: 4px 5px 0 5px;
|
||||
height: $stream-selector-height;
|
||||
|
||||
&__column-reprensentation {
|
||||
display: inline-block;
|
||||
width: 5px;
|
||||
height: $stream-selector-height - 8px;
|
||||
background-color:$font-link-primary;
|
||||
|
||||
|
||||
}
|
||||
|
||||
&:hover &__column-reprensentation{
|
||||
background-color:$font-link-primary-hover;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { StreamElement } from '../../states/streams.state';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { NavigationService } from '../../services/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-streams-selection-footer',
|
||||
|
@ -6,10 +10,25 @@ import { Component, OnInit } from '@angular/core';
|
|||
styleUrls: ['./streams-selection-footer.component.scss']
|
||||
})
|
||||
export class StreamsSelectionFooterComponent implements OnInit {
|
||||
streams: StreamElement[] = [];
|
||||
private streams$: Observable<StreamElement[]>;
|
||||
|
||||
constructor() { }
|
||||
constructor(
|
||||
private readonly navigationService: NavigationService,
|
||||
private readonly store: Store) {
|
||||
this.streams$ = this.store.select(state => state.streamsstatemodel.streams);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.streams$.subscribe((streams: StreamElement[]) => {
|
||||
this.streams = streams;
|
||||
});
|
||||
}
|
||||
|
||||
onColumnSelection(index: number): boolean {
|
||||
console.warn(`column selected: ${index}`);
|
||||
this.navigationService.columnSelected(index);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import { AccountWrapper } from "./account.models";
|
|||
import { ApiRoutes } from "../services/models/api.settings";
|
||||
import { Account, Status } from "../services/models/mastodon.interfaces";
|
||||
import { StreamingService, StreamingWrapper } from "../services/streaming.service";
|
||||
import { StreamTypeEnum } from "../states/streams.state";
|
||||
|
||||
export class Stream {
|
||||
private apiRoutes = new ApiRoutes();
|
||||
|
@ -46,22 +47,22 @@ export class Stream {
|
|||
|
||||
private getTimelineRoute(): string {
|
||||
switch (this.type) {
|
||||
case StreamTypeEnum.Home:
|
||||
case StreamTypeEnum.personnal:
|
||||
return this.apiRoutes.getHomeTimeline;
|
||||
case StreamTypeEnum.Local:
|
||||
case StreamTypeEnum.local:
|
||||
return this.apiRoutes.getPublicTimeline + `?Local=true`;
|
||||
case StreamTypeEnum.Public:
|
||||
case StreamTypeEnum.global:
|
||||
return this.apiRoutes.getPublicTimeline + `?Local=false`;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export enum StreamTypeEnum {
|
||||
Home,
|
||||
Public,
|
||||
Local
|
||||
}
|
||||
// export enum StreamTypeEnum {
|
||||
// Home,
|
||||
// Public,
|
||||
// Local
|
||||
// }
|
||||
|
||||
|
||||
export class TootWrapper {
|
||||
|
|
|
@ -43,8 +43,8 @@ export class RegisterNewAccountComponent implements OnInit {
|
|||
this.authService.getToken(appDataWrapper.instance, appInfo.app.client_id, appInfo.app.client_secret, code, appInfo.app.redirect_uri)
|
||||
.then((tokenData: TokenData) => {
|
||||
const accountInfo = new AccountInfo();
|
||||
accountInfo.username = appDataWrapper.username;
|
||||
accountInfo.instance = appDataWrapper.instance;
|
||||
accountInfo.username = appDataWrapper.username.toLowerCase();
|
||||
accountInfo.instance = appDataWrapper.instance.toLowerCase();
|
||||
accountInfo.token = tokenData;
|
||||
|
||||
this.store.dispatch([new AddAccount(accountInfo)])
|
||||
|
@ -120,7 +120,8 @@ export class RegisterNewAccountComponent implements OnInit {
|
|||
const appDataTemp = new CurrentAuthProcess(username, instance);
|
||||
localStorage.setItem('tempAuth', JSON.stringify(appDataTemp));
|
||||
|
||||
let instanceUrl = `https://${instance}/oauth/authorize?scope=${encodeURIComponent('read write follow')}&response_type=code&redirect_uri=${encodeURIComponent(app.redirect_uri)}&client_id=${app.client_id}`;
|
||||
let instanceUrl = this.authService.getInstanceLoginUrl(instance, app.client_id, app.redirect_uri);
|
||||
// let instanceUrl = `https://${instance}/oauth/authorize?scope=${encodeURIComponent('read write follow')}&response_type=code&redirect_uri=${encodeURIComponent(app.redirect_uri)}&client_id=${app.client_id}`;
|
||||
|
||||
window.location.href = instanceUrl;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<div id="mam-main-display" class="flexcroll">
|
||||
<div *ngFor="let s of streams" class="mam-stream-column">
|
||||
<app-stream [stream]="s"></app-stream>
|
||||
<div class="main-display flexcroll">
|
||||
<div class="main-display__stream-column" *ngFor="let s of streams">
|
||||
<app-stream [stream]="s" #stream></app-stream>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -1,53 +1,36 @@
|
|||
#mam-main-display {
|
||||
width: calc(100%);
|
||||
height: calc(100%);
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
/* background: black; */
|
||||
/*outline: 1px dotted red;*/
|
||||
@import "variables";
|
||||
.main-display {
|
||||
width: calc(100%);
|
||||
height: calc(100%);
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
&__stream-column {
|
||||
height: calc(100%);
|
||||
width: $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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.mam-stream-column {
|
||||
height: calc(100%);
|
||||
width: 320px;
|
||||
display: inline-block;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
white-space: normal;
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
|
||||
.flexcroll{
|
||||
scrollbar-face-color: #08090d;
|
||||
scrollbar-shadow-color: #08090d;
|
||||
scrollbar-highlight-color: #08090d;
|
||||
scrollbar-3dlight-color: #08090d;
|
||||
scrollbar-darkshadow-color: #08090d;
|
||||
scrollbar-track-color: #08090d;
|
||||
scrollbar-arrow-color: #08090d;
|
||||
}
|
||||
|
||||
/* Let's get this party started */
|
||||
.flexcroll::-webkit-scrollbar {
|
||||
/* width: 16px !important; */
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
/* .flexcroll::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
} */
|
||||
|
||||
/* Handle */
|
||||
.flexcroll::-webkit-scrollbar-thumb {
|
||||
-webkit-border-radius: 0px;
|
||||
border-radius: 0px;
|
||||
/* background: rgba(255,0,0,0.8); */
|
||||
background: #08090d;
|
||||
-webkit-box-shadow: inset 0 0 3px rgba(0,0,0,0.5);
|
||||
.flexcroll {
|
||||
scrollbar-face-color: #08090d;
|
||||
scrollbar-shadow-color: #08090d;
|
||||
scrollbar-highlight-color: #08090d;
|
||||
scrollbar-3dlight-color: #08090d;
|
||||
scrollbar-darkshadow-color: #08090d;
|
||||
scrollbar-track-color: #08090d;
|
||||
scrollbar-arrow-color: #08090d;
|
||||
&::-webkit-scrollbar {
|
||||
height: 7px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
-webkit-border-radius: 0px;
|
||||
border-radius: 0px;
|
||||
background: #08090d;
|
||||
-webkit-box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
|
@ -1,32 +1,65 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { Component, OnInit, OnDestroy, ViewChild, QueryList, ViewChildren, ElementRef } from "@angular/core";
|
||||
|
||||
import { Stream } from "../../models/stream.models";
|
||||
import { StreamsService } from "../../services/streams.service";
|
||||
import { Observable, Subscription } from "rxjs";
|
||||
import { StreamElement } from "../../states/streams.state";
|
||||
import { Store } from "@ngxs/store";
|
||||
import { Http } from "@angular/http";
|
||||
import { NavigationService } from "../../services/navigation.service";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-streams-main-display",
|
||||
templateUrl: "./streams-main-display.component.html",
|
||||
styleUrls: ["./streams-main-display.component.scss"]
|
||||
selector: "app-streams-main-display",
|
||||
templateUrl: "./streams-main-display.component.html",
|
||||
styleUrls: ["./streams-main-display.component.scss"]
|
||||
})
|
||||
export class StreamsMainDisplayComponent implements OnInit {
|
||||
streams: Stream[] = [];
|
||||
export class StreamsMainDisplayComponent implements OnInit, OnDestroy {
|
||||
|
||||
constructor(private readonly streamService: StreamsService) {
|
||||
streams: Stream[] = [];
|
||||
|
||||
private streams$: Observable<StreamElement[]>;
|
||||
private streamsStateSub: Subscription;
|
||||
private columnSelectedSub: Subscription;
|
||||
|
||||
}
|
||||
constructor(
|
||||
private readonly navigationService: NavigationService,
|
||||
private readonly http: Http,
|
||||
private readonly store: Store) {
|
||||
this.streams$ = this.store.select(state => state.streamsstatemodel.streams);
|
||||
|
||||
ngOnInit() {
|
||||
this.streamService.streamsSubject.subscribe((streams: Stream[]) => {
|
||||
for (let s of streams) {
|
||||
this.streams.push(s);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//for (let i = 0; i < 3; i++) {
|
||||
// this.streams.push(new Stream());
|
||||
//}
|
||||
}
|
||||
ngOnInit() {
|
||||
this.streamsStateSub = this.streams$.subscribe((streams: StreamElement[]) => {
|
||||
this.streams.length = 0;
|
||||
for (const stream of streams) {
|
||||
const newStream = new Stream(this.http, stream.name, stream.type);
|
||||
this.streams.push(newStream);
|
||||
}
|
||||
|
||||
this.columnSelectedSub = this.navigationService.columnSelectedSubject.subscribe((columnIndex: number) => {
|
||||
this.focusOnColumn(columnIndex);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.streamsStateSub.unsubscribe();
|
||||
this.columnSelectedSub.unsubscribe();
|
||||
}
|
||||
|
||||
@ViewChildren('stream', { read: ElementRef }) public streamsElementRef: QueryList<ElementRef>;;
|
||||
private focusOnColumn(columnIndex: number): void {
|
||||
console.warn(`col selected: ${columnIndex}`);
|
||||
|
||||
if (columnIndex > -1) {
|
||||
console.warn(this.streamsElementRef);
|
||||
|
||||
setTimeout(() => {
|
||||
this.streamsElementRef.toArray()[columnIndex].nativeElement.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'start' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Injectable } from "@angular/core";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { ApiRoutes } from './models/api.settings';
|
||||
import { AppData, TokenData } from "./models/mastodon.interfaces";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
|
@ -11,6 +12,10 @@ export class AuthService {
|
|||
private readonly httpClient: HttpClient) {
|
||||
}
|
||||
|
||||
getInstanceLoginUrl(instance: string, client_id: string, redirect_uri: string): string{
|
||||
return `https://${instance}/oauth/authorize?scope=${encodeURIComponent('read write follow')}&response_type=code&redirect_uri=${encodeURIComponent(redirect_uri)}&client_id=${client_id}`;
|
||||
}
|
||||
|
||||
getToken(instance: string, client_id: string, client_secret: string, code: string, redirect_uri: string): Promise<TokenData> {
|
||||
const url = `https://${instance}/oauth/token?client_id=${client_id}&client_secret=${client_secret}&grant_type=authorization_code&code=${code}&redirect_uri=${encodeURIComponent(redirect_uri)}`;
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { NavigationService } from './navigation.service';
|
||||
|
||||
describe('NavigationService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [NavigationService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([NavigationService], (service: NavigationService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { AccountWrapper } from '../models/account.models';
|
||||
|
||||
@Injectable()
|
||||
export class NavigationService {
|
||||
|
||||
openColumnEditorSubject = new BehaviorSubject<AccountWrapper>(null);
|
||||
columnSelectedSubject = new BehaviorSubject<number>(-1);
|
||||
|
||||
constructor() { }
|
||||
|
||||
openColumnEditor(acc: AccountWrapper) {
|
||||
this.openColumnEditorSubject.next(acc);
|
||||
}
|
||||
|
||||
closeColumnEditor() {
|
||||
this.openColumnEditorSubject.next(null);
|
||||
}
|
||||
|
||||
columnSelected(index: number): void {
|
||||
this.columnSelectedSubject.next(index);
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
import { Injectable } from "@angular/core";
|
||||
import { Http } from "@angular/http";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { Stream, StreamTypeEnum } from "../models/stream.models";
|
||||
import { AccountsService } from "./accounts.service";
|
||||
|
||||
@Injectable()
|
||||
export class StreamsService {
|
||||
streamsSubject = new BehaviorSubject<Stream[]>([]);
|
||||
|
||||
constructor(
|
||||
private readonly httpService: Http,
|
||||
// private readonly accountsService: AccountsService
|
||||
) {
|
||||
|
||||
// Return home/local/public of all accounts
|
||||
// this.accountsService.accountsSubject
|
||||
// .subscribe((accounts: LocalAccount[]) => {
|
||||
// const streams: Stream[] = [];
|
||||
// for (let acc of accounts) {
|
||||
// const homeStream = new Stream(this.httpService, "Home", StreamTypeEnum.Home, acc);
|
||||
// const localStream = new Stream(this.httpService, "Local", StreamTypeEnum.Local, acc);
|
||||
// const publicStream = new Stream(this.httpService, "Public", StreamTypeEnum.Public, acc);
|
||||
|
||||
// streams.push(homeStream);
|
||||
// streams.push(localStream);
|
||||
// streams.push(publicStream);
|
||||
// }
|
||||
// this.streamsSubject.next(streams);
|
||||
// });
|
||||
}
|
||||
|
||||
|
||||
//getStreams(): void {
|
||||
// // Return home/local/public of all accounts
|
||||
// this.accountsService.accountsSubject
|
||||
// .map((accounts: LocalAccount[]) => {
|
||||
// const streams: Stream[] = [];
|
||||
// for (let acc of accounts) {
|
||||
// const homeStream = new Stream(this.httpService, "Home", StreamTypeEnum.Home, acc);
|
||||
// const localStream = new Stream(this.httpService, "Local", StreamTypeEnum.Local, acc);
|
||||
// const publicStream = new Stream(this.httpService, "Public", StreamTypeEnum.Public, acc);
|
||||
|
||||
// streams.push(homeStream);
|
||||
// streams.push(localStream);
|
||||
// streams.push(publicStream);
|
||||
// }
|
||||
// this.streamsSubject.next(streams);
|
||||
// });
|
||||
}
|
|
@ -19,7 +19,7 @@ export interface AccountsStateModel {
|
|||
})
|
||||
export class AccountsState {
|
||||
@Action(AddAccount)
|
||||
AddRegisteredApp(ctx: StateContext<AccountsStateModel>, action: AddAccount) {
|
||||
AddAccount(ctx: StateContext<AccountsStateModel>, action: AddAccount) {
|
||||
const state = ctx.getState();
|
||||
ctx.patchState({
|
||||
accounts: [...state.accounts, action.account]
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import { State, Action, StateContext } from '@ngxs/store';
|
||||
|
||||
export class AddStream {
|
||||
static readonly type = '[Streams] Add stream';
|
||||
constructor(public stream: StreamElement) {}
|
||||
}
|
||||
|
||||
export interface StreamsStateModel {
|
||||
streams: StreamElement[];
|
||||
}
|
||||
|
||||
@State<StreamsStateModel>({
|
||||
name: 'streamsstatemodel',
|
||||
defaults: {
|
||||
streams: []
|
||||
}
|
||||
})
|
||||
export class StreamsState {
|
||||
@Action(AddStream)
|
||||
AddStream(ctx: StateContext<StreamsStateModel>, action: AddStream) {
|
||||
const state = ctx.getState();
|
||||
ctx.patchState({
|
||||
streams: [...state.streams, action.stream]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class StreamElement {
|
||||
constructor(public type: StreamTypeEnum, public name: string, public username: string) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export enum StreamTypeEnum {
|
||||
unknown = 0,
|
||||
global = 1,
|
||||
local = 2,
|
||||
personnal = 3,
|
||||
favorites = 4,
|
||||
activity = 5,
|
||||
list = 6,
|
||||
directmessages = 7,
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
@mixin clearfix {
|
||||
&::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,18 @@
|
|||
$font-color-primary: #e8eaf3;
|
||||
$font-color-secondary: darken(#fff, 25);
|
||||
|
||||
$font-link-primary: #595c67;
|
||||
$font-link-primary-hover: #8f93a2;
|
||||
|
||||
$color-primary: #141824;
|
||||
$color-secondary: #090b10;
|
||||
|
||||
$default-font-size: 15px;
|
||||
$small-font-size: 12px;
|
||||
|
||||
|
||||
// Block dispositions
|
||||
$stream-selector-height: 30px;
|
||||
|
||||
$stream-column-separator: 7px;
|
||||
$stream-column-width: 320px;
|
Loading…
Reference in New Issue