mirror of
https://github.com/block-core/blockcore-notes.git
synced 2024-09-29 22:40:44 +00:00
Merge pull request #124 from block-core/new-state-management
WIP: New state management
This commit is contained in:
commit
8350889b8d
@ -33,6 +33,7 @@ import { LoginComponent } from './connect/login/login';
|
||||
import { CreateProfileComponent } from './connect/create/create';
|
||||
import { EditorBadgesComponent } from './editor-badges/editor';
|
||||
import { BadgeComponent } from './badge/badge';
|
||||
import { ExampleComponent } from './example/example';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@ -245,7 +246,7 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'about',
|
||||
loadChildren: () => import('./about/about.module').then(m => m.AboutModule)
|
||||
loadChildren: () => import('./about/about.module').then((m) => m.AboutModule),
|
||||
// component: AboutComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// resolve: {
|
||||
@ -284,6 +285,14 @@ const routes: Routes = [
|
||||
data: LoadingResolverService,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'example',
|
||||
component: ExampleComponent,
|
||||
canActivate: [AuthGuard],
|
||||
resolve: {
|
||||
data: LoadingResolverService,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'queue',
|
||||
component: QueueComponent,
|
||||
|
@ -110,6 +110,10 @@
|
||||
<!-- <a [routerLink]="['/development']" mat-menu-item (click)="toggleMenu()" [routerLinkActiveOptions]="{ exact: true }" routerLinkActive="active">
|
||||
<mat-icon>construction</mat-icon>
|
||||
<span *ngIf="displayLabels">Development</span>
|
||||
</a>
|
||||
<a [routerLink]="['/example']" mat-menu-item (click)="toggleMenu()" [routerLinkActiveOptions]="{ exact: true }" routerLinkActive="active">
|
||||
<mat-icon>construction</mat-icon>
|
||||
<span *ngIf="displayLabels">Example</span>
|
||||
</a> -->
|
||||
<a [routerLink]="['/relays']" mat-menu-item (click)="toggleMenu()" [routerLinkActiveOptions]="{ exact: true }" routerLinkActive="active">
|
||||
<mat-icon>dns</mat-icon>
|
||||
|
@ -153,6 +153,7 @@ import { BadgeComponent } from './badge/badge';
|
||||
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
||||
import { DragScrollModule } from 'ngx-drag-scroll';
|
||||
import { ZappersListDialogComponent } from './shared/zappers-list-dialog/zappers-list-dialog.component';
|
||||
import { ExampleComponent } from './example/example';
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
@ -244,6 +245,7 @@ import { ZappersListDialogComponent } from './shared/zappers-list-dialog/zappers
|
||||
TagsComponent,
|
||||
BadgeComponent,
|
||||
ZappersListDialogComponent,
|
||||
ExampleComponent
|
||||
],
|
||||
imports: [
|
||||
HttpClientModule,
|
||||
|
@ -27,6 +27,8 @@ import { OptionsService } from './services/options';
|
||||
import { LabelService } from './services/label';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { BadgeService } from './services/badge';
|
||||
import { State } from './services/state';
|
||||
import { EventService } from './services/event';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@ -66,7 +68,9 @@ export class AppComponent {
|
||||
public ui: UIService,
|
||||
private bottomSheet: MatBottomSheet,
|
||||
public searchService: SearchService,
|
||||
public theme: ThemeService
|
||||
public theme: ThemeService,
|
||||
private state: State,
|
||||
private eventService: EventService
|
||||
) {
|
||||
if (!this.visibilityHandler) {
|
||||
this.visibilityHandler = addEventListener('visibilitychange', (event) => {
|
||||
@ -96,7 +100,8 @@ export class AppComponent {
|
||||
}
|
||||
|
||||
this.authService.authInfo$.subscribe(async (auth) => {
|
||||
auth.publicKeyHex;
|
||||
this.state.pubkey = auth.publicKeyHex;
|
||||
|
||||
|
||||
this.authenticated = auth.authenticated();
|
||||
|
||||
|
@ -1,4 +1,93 @@
|
||||
<div class="page">
|
||||
<h1>State Service Management</h1>
|
||||
|
||||
<mat-list >
|
||||
<div mat-subheader>Metadata</div>
|
||||
<mat-list-item *ngFor="let state of state.events.metadata | keyvalue">
|
||||
<mat-icon matListItemIcon>folder</mat-icon>
|
||||
<div matListItemTitle>{{state.key}}</div>
|
||||
<div matListItemLine>{{state.value.content}}</div>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
|
||||
<mat-list >
|
||||
<div mat-subheader>Text</div>
|
||||
<mat-list-item *ngFor="let state of state.events.shortTextNote | keyvalue">
|
||||
<mat-icon matListItemIcon>folder</mat-icon>
|
||||
<div matListItemTitle>{{state.key}}</div>
|
||||
<div matListItemLine>{{state.value.content}}</div>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
|
||||
<mat-list >
|
||||
<div mat-subheader>Contacts</div>
|
||||
<mat-list-item *ngFor="let state of state.events.contacts | keyvalue">
|
||||
<mat-icon matListItemIcon>folder</mat-icon>
|
||||
<div matListItemTitle>{{state.key}}</div>
|
||||
<div matListItemLine>{{state.value.content}}</div>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
|
||||
<mat-list >
|
||||
<div mat-subheader>Reactions</div>
|
||||
<mat-list-item *ngFor="let state of state.events.reaction | keyvalue">
|
||||
<mat-icon matListItemIcon>folder</mat-icon>
|
||||
<div matListItemTitle>{{state.key}}</div>
|
||||
<div matListItemLine>{{state.value.content}}</div>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
|
||||
<mat-list >
|
||||
<div mat-subheader>Reposts</div>
|
||||
<mat-list-item *ngFor="let state of state.events.reposts| keyvalue">
|
||||
<mat-icon matListItemIcon>folder</mat-icon>
|
||||
<div matListItemTitle>{{state.key}}</div>
|
||||
<div matListItemLine>{{state.value.content}}</div>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
|
||||
<mat-list >
|
||||
<div mat-subheader>Zap</div>
|
||||
<mat-list-item *ngFor="let state of state.events.zap | keyvalue">
|
||||
<mat-icon matListItemIcon>folder</mat-icon>
|
||||
<div matListItemTitle>{{state.key}}</div>
|
||||
<div matListItemLine>{{state.value.content}}</div>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
|
||||
<mat-list >
|
||||
<div mat-subheader>Zap Request</div>
|
||||
<mat-list-item *ngFor="let state of state.events.zapRequest| keyvalue">
|
||||
<mat-icon matListItemIcon>folder</mat-icon>
|
||||
<div matListItemTitle>{{state.key}}</div>
|
||||
<div matListItemLine>{{state.value.content}}</div>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
|
||||
<mat-list >
|
||||
<div mat-subheader>Article</div>
|
||||
<mat-list-item *ngFor="let state of state.events.longFormContent | keyvalue">
|
||||
<mat-icon matListItemIcon>folder</mat-icon>
|
||||
<div matListItemTitle>{{state.key}}</div>
|
||||
<div matListItemLine>{{state.value.content}}</div>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
|
||||
|
||||
|
||||
State as JSON:<br>
|
||||
{{ state | json }}
|
||||
|
||||
<br /><br />
|
||||
|
||||
<p>This page act as examples for more specialized implementation details of the app.</p>
|
||||
|
||||
<button mat-stroked-button (click)="downloadProfile()">Enque Profile Download</button>
|
||||
@ -21,4 +110,4 @@
|
||||
<app-relays [relays]="relayService.items"></app-relays>
|
||||
|
||||
<!-- <mat-spinner></mat-spinner> -->
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,6 +5,7 @@ import { NostrService } from '../services/nostr';
|
||||
import { RelayService } from '../services/relay';
|
||||
import { RelayType } from '../types/relay';
|
||||
import { Storage } from '../types/storage';
|
||||
import { State, StateService } from '../services/state';
|
||||
|
||||
@Component({
|
||||
selector: 'app-development',
|
||||
@ -15,10 +16,13 @@ export class DevelopmentComponent {
|
||||
worker?: Worker;
|
||||
storage?: Storage;
|
||||
|
||||
constructor(private nostr: NostrService, private dataService: DataService, private appState: ApplicationState, public relayService: RelayService) {}
|
||||
constructor(
|
||||
public state: State,
|
||||
private nostr: NostrService, private dataService: DataService, private appState: ApplicationState, public relayService: RelayService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.appState.updateTitle('Development & Debug');
|
||||
|
||||
}
|
||||
|
||||
async database() {
|
||||
|
19
src/app/example/example.css
Normal file
19
src/app/example/example.css
Normal file
@ -0,0 +1,19 @@
|
||||
.example-viewport {
|
||||
height: 100%;
|
||||
min-height: 500px;
|
||||
width: 100%;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.example-item {
|
||||
box-sizing: border-box;
|
||||
height: 200px;
|
||||
background-color: purple;
|
||||
}
|
||||
|
||||
.example-item-content {
|
||||
overflow: scroll;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border: 1px solid green;
|
||||
}
|
12
src/app/example/example.html
Normal file
12
src/app/example/example.html
Normal file
@ -0,0 +1,12 @@
|
||||
<div class="feed-page">
|
||||
<p>This example demonstrates how to do sorting, filtering, virtual scrolling, dynamic updates of complex data within Blockcore Notes.</p>
|
||||
|
||||
<cdk-virtual-scroll-viewport itemSize="200" class="example-viewport" #scrollViewport>
|
||||
<div *cdkVirtualFor="let item of state.events.shortTextNote | keyvalue" class="example-item">
|
||||
|
||||
{{item.value.id}}
|
||||
|
||||
<div class="example-item-content">{{item.value.content}}</div>
|
||||
</div>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
</div>
|
52
src/app/example/example.ts
Normal file
52
src/app/example/example.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { ApplicationState } from '../services/applicationstate';
|
||||
import { State } from '../services/state';
|
||||
|
||||
@Component({
|
||||
selector: 'app-example',
|
||||
templateUrl: 'example.html',
|
||||
styleUrls: ['example.css'],
|
||||
// changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
@ViewChild('scrollViewport')
|
||||
private cdkVirtualScrollViewport: any;
|
||||
|
||||
items = Array.from({ length: 10000 }).map((_, i) => `Item #${i + 1}`);
|
||||
|
||||
constructor(public state: State, private appState: ApplicationState) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.appState.updateTitle('Example');
|
||||
}
|
||||
|
||||
calculateContainerHeight(): string {
|
||||
const numberOfItems = this.items.length;
|
||||
// This should be the height of your item in pixels
|
||||
const itemHeight = 20;
|
||||
// The final number of items you want to keep visible
|
||||
const visibleItems = 10;
|
||||
|
||||
setTimeout(() => {
|
||||
// Makes CdkVirtualScrollViewport to refresh its internal size values after
|
||||
// changing the container height. This should be delayed with a "setTimeout"
|
||||
// because we want it to be executed after the container has effectively
|
||||
// changed its height. Another option would be a resize listener for the
|
||||
// container and call this line there but it may requires a library to detect
|
||||
// the resize event.
|
||||
|
||||
this.cdkVirtualScrollViewport.checkViewportSize();
|
||||
}, 300);
|
||||
|
||||
// It calculates the container height for the first items in the list
|
||||
// It means the container will expand until it reaches `200px` (20 * 10)
|
||||
// and will keep this size.
|
||||
if (numberOfItems <= visibleItems) {
|
||||
return `${itemHeight * numberOfItems}px`;
|
||||
}
|
||||
|
||||
// This function is called from the template so it ensures the container will have
|
||||
// the final height if number of items are greater than the value in "visibleItems".
|
||||
return `${itemHeight * visibleItems}px`;
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
|
||||
.loading-container {
|
||||
text-align: center;
|
||||
}
|
||||
@ -7,3 +6,6 @@
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.circle-selection {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
@ -12,6 +12,13 @@
|
||||
</div> -->
|
||||
|
||||
<div class="feed-page">
|
||||
|
||||
<mat-button-toggle-group class="circle-selection" name="ingredients">
|
||||
<mat-button-toggle [routerLink]="['/feed', circle.id]" [matTooltip]="circle.name" value="flour" *ngFor="let circle of circleService.circles">
|
||||
<mat-icon matListItemIcon [style.color]="circle.color">trip_origin</mat-icon>
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
|
||||
<mat-accordion class="options">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
|
@ -13,6 +13,7 @@ import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { StorageService } from '../services/storage';
|
||||
import { dexieToRx } from '../shared/utilities';
|
||||
import { UIService } from '../services/ui';
|
||||
import { CircleService } from '../services/circle';
|
||||
|
||||
@Component({
|
||||
selector: 'app-feed-private',
|
||||
@ -42,6 +43,7 @@ export class FeedPrivateComponent {
|
||||
// }
|
||||
|
||||
constructor(
|
||||
public circleService: CircleService,
|
||||
public ui: UIService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
public db: StorageService,
|
||||
|
@ -7,7 +7,8 @@
|
||||
<!-- <div *ngIf="profileService.item$ | async as profile">
|
||||
{{ profile.name }}
|
||||
</div> -->
|
||||
|
||||
|
||||
<div class="page">
|
||||
<ng-container *ngIf="ui.profile$ | async as profile">
|
||||
<!-- <div class="tab-panel-viewport" cdkVirtualScrollingElement>
|
||||
<cdk-virtual-scroll-viewport scrollWindow itemSize="1">
|
||||
@ -23,6 +24,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<!-- <div class="page" *ngIf="ui.profile$ | async as profile">
|
||||
<app-profile-widget *ngFor="let pubkey of virtualList.view" [pubkey]="pubkey"></app-profile-widget>
|
||||
|
@ -100,7 +100,7 @@ export class PeopleComponent {
|
||||
});
|
||||
} else if (sorting === 'followed-desc') {
|
||||
this.sortedItems = this.items.sort((a, b) => {
|
||||
return a.followed! < b.followed! ? -1 : 1;
|
||||
return a.followed! > b.followed! ? 1 : -1;
|
||||
});
|
||||
} else if (sorting === 'created-asc') {
|
||||
this.sortedItems = this.items.sort((a, b) => {
|
||||
|
@ -9,15 +9,58 @@ export class StateService {
|
||||
constructor(private state: State) {}
|
||||
|
||||
addEvent(event: NostrEvent) {
|
||||
return;
|
||||
|
||||
// TODO: Temporarily removed to avoid building massive in-memory state.
|
||||
// switch (event.kind) {
|
||||
// case Kind.Metadata:
|
||||
// this.addIfNewer(event, this.state.events.shortTextNote);
|
||||
// break;
|
||||
// case Kind.Text:
|
||||
// this.addIfMissing(event, this.state.events.shortTextNote);
|
||||
// break;
|
||||
// }
|
||||
switch (event.kind as any) {
|
||||
case Kind.Metadata:
|
||||
this.addIfNewer(event, event.pubkey, this.state.events.metadata);
|
||||
if (this.state.pubkey == event.pubkey) {
|
||||
this.state.metadata = event;
|
||||
}
|
||||
break;
|
||||
case Kind.Text:
|
||||
this.addIfMissing(event, this.state.events.shortTextNote);
|
||||
break;
|
||||
case Kind.Contacts:
|
||||
this.addIfNewer(event, event.pubkey, this.state.events.contacts);
|
||||
break;
|
||||
case Kind.Reaction:
|
||||
this.addIfMissing(event, this.state.events.reaction);
|
||||
break;
|
||||
case 6:
|
||||
this.addIfMissing(event, this.state.events.reposts);
|
||||
break;
|
||||
case Kind.Zap:
|
||||
this.addIfMissing(event, this.state.events.zap);
|
||||
break;
|
||||
case Kind.ZapRequest:
|
||||
this.addIfMissing(event, this.state.events.zapRequest);
|
||||
break;
|
||||
case Kind.Article:
|
||||
const slug = this.firstDTag(event);
|
||||
this.addIfNewer(event, slug!, this.state.events.longFormContent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tagsOfType(event: NostrEvent | null, type: string) {
|
||||
if (!event) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const tags = event.tags.filter((t) => t[0] === type);
|
||||
return tags;
|
||||
}
|
||||
|
||||
firstDTag(event: NostrEvent | null | any) {
|
||||
const tags = this.tagsOfType(event, 'd');
|
||||
|
||||
if (tags.length == 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return tags[0][1];
|
||||
}
|
||||
|
||||
addIfMissing(event: NostrEvent, map: Map<string, NostrEvent>) {
|
||||
@ -28,17 +71,17 @@ export class StateService {
|
||||
map.set(event.id, event);
|
||||
}
|
||||
|
||||
addIfNewer(event: NostrEvent, map: Map<string, NostrEvent>) {
|
||||
if (!map.has(event.id)) {
|
||||
map.set(event.id, event);
|
||||
addIfNewer(event: NostrEvent, identifier: string, map: Map<string, NostrEvent>) {
|
||||
if (!map.has(identifier)) {
|
||||
map.set(identifier, event);
|
||||
} else {
|
||||
const existing = map.get(event.id);
|
||||
const existing = map.get(identifier);
|
||||
|
||||
if (existing!.created_at > event.created_at) {
|
||||
if (existing!.created_at >= event.created_at) {
|
||||
return;
|
||||
}
|
||||
|
||||
map.set(event.id, event);
|
||||
map.set(identifier, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,6 +94,10 @@ export class State {
|
||||
|
||||
circles: Circle[] = [];
|
||||
|
||||
metadata?: NostrEvent;
|
||||
|
||||
pubkey?: String;
|
||||
|
||||
events: EventsState = {
|
||||
metadata: new Map(),
|
||||
shortTextNote: new Map(),
|
||||
|
@ -15,6 +15,12 @@
|
||||
<ng-container *ngFor="let token of dynamicText">
|
||||
<ng-template [ngIf]="isString(token)">{{ token }}</ng-template>
|
||||
<ng-template [ngIf]="!isString(token) && isFollowing" [ngSwitch]="token.token">
|
||||
|
||||
<ng-container *ngSwitchCase="'npub'"><a class="reply-link" [routerLink]="['/p', token.word]">@{{ getDisplayName(token.word) }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'nprofile'"><a class="reply-link" [routerLink]="['/p', token.word]">@{{ getDisplayName(token.word) }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'note'"><a class="reply-link" [routerLink]="['/e', token.word]">{{ token.word }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'nevent'"><a class="reply-link" [routerLink]="['/e', token.word]">{{ token.word }}</a></ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'username'"><a class="reply-link" [routerLink]="['/p', token.word]">@{{ getDisplayName(token.word) }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'link'"><a [href]="[token.word]" target="_blank">{{ token.word }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'image'"><img mat-card-image class="event-image" loading="lazy" decoding="async" [matTooltip]="token.word" [alt]="token.word" [src]="token.safeWord" (click)="expandImage(token.word)" /></ng-container>
|
||||
@ -47,6 +53,12 @@
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngIf]="!isString(token) && !isFollowing" [ngSwitch]="token.token">
|
||||
|
||||
<ng-container *ngSwitchCase="'npub'"><a class="reply-link" [routerLink]="['/p', token.word]">@{{ getDisplayName(token.word) }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'nprofile'"><a class="reply-link" [routerLink]="['/p', token.word]">@{{ getDisplayName(token.word) }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'note'"><a class="reply-link" [routerLink]="['/e', token.word]">{{ token.word }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'nevent'"><a class="reply-link" [routerLink]="['/e', token.word]">{{ token.word }}</a></ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'username'"><a class="reply-link" [routerLink]="['/p', token.word]">@{{ getDisplayName(token.word) }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'link'"><a [href]="[token.word]" target="_blank">{{ token.word }}</a></ng-container>
|
||||
<ng-container *ngSwitchCase="'image'"><a [href]="[token.word]" target="_blank">{{ token.word }}</a></ng-container>
|
||||
|
@ -9,6 +9,7 @@ import { ProfileService } from 'src/app/services/profile';
|
||||
import { Utilities } from 'src/app/services/utilities';
|
||||
import { NostrEventDocument, NostrProfile, NostrProfileDocument, TokenKeyword } from '../../services/interfaces';
|
||||
import { ProfileImageDialog } from '../profile-image-dialog/profile-image-dialog';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
|
||||
interface MediaItem {
|
||||
url: SafeResourceUrl;
|
||||
@ -132,6 +133,7 @@ export class ContentComponent {
|
||||
}
|
||||
|
||||
getDisplayName(pubkey: string) {
|
||||
pubkey = this.utilities.ensureHexIdentifier(pubkey);
|
||||
const profile = this.profileService.getCachedProfile(pubkey);
|
||||
|
||||
if (!profile) {
|
||||
@ -281,6 +283,21 @@ export class ContentComponent {
|
||||
}
|
||||
|
||||
i = res.push(keyword);
|
||||
} else if (token.startsWith('nostr:')) {
|
||||
const decoded = nip19.decode(token.substring(6));
|
||||
const val = decoded.data as any;
|
||||
|
||||
if (decoded.type === 'nprofile') {
|
||||
i = res.push({ safeWord: this.utilities.sanitizeUrlAndBypass(token), word: val.pubkey, token: decoded.type });
|
||||
} else if (decoded.type === 'npub') {
|
||||
i = res.push({ safeWord: this.utilities.sanitizeUrlAndBypass(token), word: val, token: decoded.type });
|
||||
} else if (decoded.type === 'note') {
|
||||
i = res.push({ safeWord: this.utilities.sanitizeUrlAndBypass(token), word: val, token: decoded.type });
|
||||
} else if (decoded.type === 'nevent') {
|
||||
i = res.push({ safeWord: this.utilities.sanitizeUrlAndBypass(token), word: val.id, token: decoded.type });
|
||||
} else {
|
||||
i = res.push({ safeWord: this.utilities.sanitizeUrlAndBypass(token), word: token.substring(6), token: decoded.type });
|
||||
}
|
||||
} else if (token.startsWith('http://') || token.startsWith('https://')) {
|
||||
if (this.isImage(token)) {
|
||||
i = res.push({ safeWord: this.utilities.sanitizeUrlAndBypass(token), word: token, token: 'image' });
|
||||
|
Loading…
Reference in New Issue
Block a user