diff --git a/frontend/src/app/lightning/channel/channel-preview.component.html b/frontend/src/app/lightning/channel/channel-preview.component.html
new file mode 100644
index 000000000..cfb2c2714
--- /dev/null
+++ b/frontend/src/app/lightning/channel/channel-preview.component.html
@@ -0,0 +1,72 @@
+
+
+
+
+
Inactive
+
Active
+
Closed
+
+
+
+
+
+
+ {{ channel.node_left.alias || '?' }}
+
+
+
+ {{ channel.node_right.alias || '?' }}
+
+
+
+
+
+
+
+
+ Created |
+ {{ channel.created | date:'yyyy-MM-dd HH:mm' }} |
+
+
+ Capacity |
+ |
+
+
+ Fee rate |
+
+
+ {{ channel.node_left.fee_rate }} ppm
+
+ {{ channel.node_right.fee_rate }} ppm
+
+ |
+
+
+ Base fee |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ Error loading data.
+
+ {{ error.status }}: {{ error.error }}
+
+
diff --git a/frontend/src/app/lightning/channel/channel-preview.component.scss b/frontend/src/app/lightning/channel/channel-preview.component.scss
new file mode 100644
index 000000000..e89733ff3
--- /dev/null
+++ b/frontend/src/app/lightning/channel/channel-preview.component.scss
@@ -0,0 +1,76 @@
+.title {
+ font-size: 52px;
+ margin: 0;
+}
+
+.table {
+ font-size: 32px;
+ margin-top: 36px;
+}
+
+.badges {
+ font-size: 28px;
+
+ ::ng-deep .badge {
+ margin-left: 0.5em;
+ }
+}
+
+.row {
+ margin-right: 0;
+}
+
+.full-width-row {
+ padding-left: 15px;
+ padding-right: 15px;
+
+ &:nth-child(even) {
+ background: #181b2d;
+ margin: 15px 0;
+ }
+}
+
+.nodes {
+ font-size: 36px;
+ align-items: center;
+}
+
+.between-arrow {
+ font-size: 24px;
+}
+
+.map-col {
+ flex-grow: 0;
+ flex-shrink: 0;
+ width: 470px;
+ min-width: 470px;
+ padding: 0;
+ background: #181b2d;
+ max-height: 470px;
+ overflow: hidden;
+}
+
+::ng-deep .symbol {
+ font-size: 24px;
+}
+
+.dual-cell {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: baseline;
+
+ & > * {
+ width: 0;
+ flex-grow: 1;
+
+ &:nth-child(2) {
+ text-align: center;
+ max-width: 1.5em;
+ }
+ &:nth-child(3) {
+ text-align: right;
+ }
+ }
+}
diff --git a/frontend/src/app/lightning/channel/channel-preview.component.ts b/frontend/src/app/lightning/channel/channel-preview.component.ts
new file mode 100644
index 000000000..fb3055d43
--- /dev/null
+++ b/frontend/src/app/lightning/channel/channel-preview.component.ts
@@ -0,0 +1,67 @@
+import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
+import { ActivatedRoute, ParamMap } from '@angular/router';
+import { Observable, of } from 'rxjs';
+import { catchError, switchMap, tap } from 'rxjs/operators';
+import { SeoService } from 'src/app/services/seo.service';
+import { OpenGraphService } from 'src/app/services/opengraph.service';
+import { LightningApiService } from '../lightning-api.service';
+
+@Component({
+ selector: 'app-channel-preview',
+ templateUrl: './channel-preview.component.html',
+ styleUrls: ['./channel-preview.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ChannelPreviewComponent implements OnInit {
+ channel$: Observable;
+ error: any = null;
+ channelGeo: number[] = [];
+
+ constructor(
+ private lightningApiService: LightningApiService,
+ private activatedRoute: ActivatedRoute,
+ private seoService: SeoService,
+ private openGraphService: OpenGraphService,
+ ) { }
+
+ ngOnInit(): void {
+ this.channel$ = this.activatedRoute.paramMap
+ .pipe(
+ switchMap((params: ParamMap) => {
+ this.openGraphService.waitFor('channel-map');
+ this.openGraphService.waitFor('channel-data');
+ this.error = null;
+ this.seoService.setTitle(`Channel: ${params.get('short_id')}`);
+ return this.lightningApiService.getChannel$(params.get('short_id'))
+ .pipe(
+ tap((data) => {
+ if (!data.node_left.longitude || !data.node_left.latitude ||
+ !data.node_right.longitude || !data.node_right.latitude) {
+ this.channelGeo = [];
+ } else {
+ this.channelGeo = [
+ data.node_left.public_key,
+ data.node_left.alias,
+ data.node_left.longitude, data.node_left.latitude,
+ data.node_right.public_key,
+ data.node_right.alias,
+ data.node_right.longitude, data.node_right.latitude,
+ ];
+ }
+ this.openGraphService.waitOver('channel-data');
+ }),
+ catchError((err) => {
+ this.error = err;
+ this.openGraphService.waitOver('channel-map');
+ this.openGraphService.waitOver('channel-data');
+ return of(null);
+ })
+ );
+ })
+ );
+ }
+
+ onMapReady() {
+ this.openGraphService.waitOver('channel-map');
+ }
+}
diff --git a/frontend/src/app/lightning/lightning-previews.module.ts b/frontend/src/app/lightning/lightning-previews.module.ts
index d3a08dff6..4d5d6cee9 100644
--- a/frontend/src/app/lightning/lightning-previews.module.ts
+++ b/frontend/src/app/lightning/lightning-previews.module.ts
@@ -7,9 +7,11 @@ import { LightningModule } from './lightning.module';
import { LightningApiService } from './lightning-api.service';
import { NodePreviewComponent } from './node/node-preview.component';
import { LightningPreviewsRoutingModule } from './lightning-previews.routing.module';
+import { ChannelPreviewComponent } from './channel/channel-preview.component';
@NgModule({
declarations: [
NodePreviewComponent,
+ ChannelPreviewComponent,
],
imports: [
CommonModule,
diff --git a/frontend/src/app/lightning/lightning-previews.routing.module.ts b/frontend/src/app/lightning/lightning-previews.routing.module.ts
index e499cc5c7..69de2aadf 100644
--- a/frontend/src/app/lightning/lightning-previews.routing.module.ts
+++ b/frontend/src/app/lightning/lightning-previews.routing.module.ts
@@ -1,12 +1,17 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { NodePreviewComponent } from './node/node-preview.component';
+import { ChannelPreviewComponent } from './channel/channel-preview.component';
const routes: Routes = [
{
path: 'node/:public_key',
component: NodePreviewComponent,
},
+ {
+ path: 'channel/:short_id',
+ component: ChannelPreviewComponent,
+ },
{
path: '**',
redirectTo: ''