Multicolumn Bluesky client powered by Angular

feat: loading spinner

kbenlloch 79037af6 debef20c

+6
src/app/components/aux-panes/thread-view/thread-view.component.html
··· 29 29 30 30 <divider/> 31 31 </div> 32 + } @else { 33 + <div 34 + class="h-full w-full flex justify-center mt-16 text-4xl" 35 + > 36 + <spinner/> 37 + </div> 32 38 } 33 39 34 40 <ng-template
+3 -1
src/app/components/aux-panes/thread-view/thread-view.component.ts
··· 21 21 import {DialogService} from '@services/dialog.service'; 22 22 import {NgTemplateOutlet} from '@angular/common'; 23 23 import {DividerComponent} from '@components/shared/divider/divider.component'; 24 + import {SpinnerComponent} from '@components/shared/spinner/spinner.component'; 24 25 25 26 @Component({ 26 27 selector: 'thread-view', ··· 30 31 IsFeedDefsBlockedPostPipe, 31 32 PostCardComponent, 32 33 NgTemplateOutlet, 33 - DividerComponent 34 + DividerComponent, 35 + SpinnerComponent 34 36 ], 35 37 templateUrl: './thread-view.component.html', 36 38 changeDetection: ChangeDetectionStrategy.OnPush
+6 -10
src/app/components/feeds/author-feed/author-feed.component.html
··· 27 27 28 28 <divider/> 29 29 } 30 - <!-- } @else {--> 31 - <!-- <div--> 32 - <!-- class="h-full w-full flex items-center justify-center"--> 33 - <!-- >--> 34 - <!-- <p-progress-spinner--> 35 - <!-- class="h-12"--> 36 - <!-- strokeWidth="5"--> 37 - <!-- [style]="{height: '3rem', width: '3rem'}"--> 38 - <!-- />--> 39 - <!-- </div>--> 30 + } @else { 31 + <div 32 + class="h-full w-full flex justify-center mt-16 text-4xl" 33 + > 34 + <spinner/> 35 + </div> 40 36 } 41 37 </div>
+2
src/app/components/feeds/author-feed/author-feed.component.ts
··· 23 23 import {GroupedPost} from '@models/grouped-post'; 24 24 import {PostCardGrandParentPipe} from '@shared/pipes/post-card-grandparent.pipe'; 25 25 import {PostCardParentPipe} from '@shared/pipes/post-card-parent.pipe'; 26 + import {SpinnerComponent} from '@components/shared/spinner/spinner.component'; 26 27 27 28 @Component({ 28 29 selector: 'author-feed', ··· 33 34 DividerComponent, 34 35 PostCardGrandParentPipe, 35 36 PostCardParentPipe, 37 + SpinnerComponent, 36 38 ], 37 39 templateUrl: './author-feed.component.html', 38 40 changeDetection: ChangeDetectionStrategy.OnPush
+6 -10
src/app/components/feeds/notification-feed/notification-feed.component.html
··· 25 25 26 26 <divider/> 27 27 } 28 - <!-- } @else {--> 29 - <!-- <div--> 30 - <!-- class="h-full w-full flex items-center justify-center"--> 31 - <!-- >--> 32 - <!-- <p-progress-spinner--> 33 - <!-- class="h-12"--> 34 - <!-- strokeWidth="5"--> 35 - <!-- [style]="{height: '3rem', width: '3rem'}"--> 36 - <!-- />--> 37 - <!-- </div>--> 28 + } @else { 29 + <div 30 + class="h-full w-full flex justify-center mt-16 text-4xl" 31 + > 32 + <spinner/> 33 + </div> 38 34 } 39 35 </div>
+2
src/app/components/feeds/notification-feed/notification-feed.component.ts
··· 20 20 import {MessageService} from '@services/message.service'; 21 21 import {DividerComponent} from '@components/shared/divider/divider.component'; 22 22 import {DialogService} from '@services/dialog.service'; 23 + import {SpinnerComponent} from '@components/shared/spinner/spinner.component'; 23 24 24 25 @Component({ 25 26 selector: 'notification-feed', ··· 30 31 IsNotificationArrayPipe, 31 32 NotificationCardComponent, 32 33 DividerComponent, 34 + SpinnerComponent, 33 35 ], 34 36 templateUrl: './notification-feed.component.html', 35 37 changeDetection: ChangeDetectionStrategy.OnPush
+6 -10
src/app/components/feeds/timeline-feed/timeline-feed.component.html
··· 27 27 28 28 <divider/> 29 29 } 30 - <!-- } @else {--> 31 - <!-- <div--> 32 - <!-- class="h-full w-full flex items-center justify-center"--> 33 - <!-- >--> 34 - <!-- <p-progress-spinner--> 35 - <!-- class="h-12"--> 36 - <!-- strokeWidth="5"--> 37 - <!-- [style]="{height: '3rem', width: '3rem'}"--> 38 - <!-- />--> 39 - <!-- </div>--> 30 + } @else { 31 + <div 32 + class="h-full w-full flex justify-center mt-16 text-4xl" 33 + > 34 + <spinner/> 35 + </div> 40 36 } 41 37 </div>
+2
src/app/components/feeds/timeline-feed/timeline-feed.component.ts
··· 23 23 import {FeedService} from '@services/feed.service'; 24 24 import {PostCardGrandParentPipe} from '@shared/pipes/post-card-grandparent.pipe'; 25 25 import {PostCardParentPipe} from '@shared/pipes/post-card-parent.pipe'; 26 + import {SpinnerComponent} from '@components/shared/spinner/spinner.component'; 26 27 27 28 @Component({ 28 29 selector: 'timeline-feed', ··· 33 34 DividerComponent, 34 35 PostCardGrandParentPipe, 35 36 PostCardParentPipe, 37 + SpinnerComponent, 36 38 ], 37 39 templateUrl: './timeline-feed.component.html', 38 40 changeDetection: ChangeDetectionStrategy.OnPush
+8 -1
src/app/components/navigation/post-composer/post-composer.component.html
··· 178 178 <button 179 179 class="btn-secondary h-9 flex-1 border-0 p-0 flex items-center justify-center" 180 180 (click)="uploader.click()" 181 + [disabled]="(mediaEmbed | isMediaEmbedImage) ? mediaEmbed.images.length == 4 : mediaEmbed" 181 182 > 182 183 <span 183 184 class="material-icons-outlined !text-xl" ··· 223 224 class="btn-primary font-semibold h-16 w-full border-0 border-l" 224 225 [disabled]="loading || text.innerText.length > 300 || (!text.innerText.length && !mediaEmbed && !recordEmbed)" 225 226 (click)="publishPost()" 226 - >post</button> 227 + >post 228 + @if (loading) { 229 + <spinner 230 + class="absolute ml-2 mt-0.5" 231 + /> 232 + } 233 + </button> 227 234 </div> 228 235 </div> 229 236 </div>
+3 -1
src/app/components/navigation/post-composer/post-composer.component.ts
··· 32 32 import {IsGraphDefsStarterPackViewPipe} from '@shared/pipes/type-guards/is-graph-defs-starterpack-view'; 33 33 import {ExternalEmbedComponent} from '@components/embeds/external-embed/external-embed.component'; 34 34 import {MessageService} from '@services/message.service'; 35 + import {SpinnerComponent} from '@components/shared/spinner/spinner.component'; 35 36 36 37 @Component({ 37 38 selector: 'post-composer', ··· 51 52 IsFeedDefsGeneratorViewPipe, 52 53 IsGraphDefsListViewPipe, 53 54 IsGraphDefsStarterPackViewPipe, 54 - ExternalEmbedComponent 55 + ExternalEmbedComponent, 56 + SpinnerComponent 55 57 ], 56 58 templateUrl: './post-composer.component.html', 57 59 styles: `
+32
src/app/components/shared/spinner/spinner.component.ts
··· 1 + import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy} from '@angular/core'; 2 + 3 + @Component({ 4 + selector: 'spinner', 5 + imports: [], 6 + template: ` 7 + <div 8 + class="flex h-[1em] w-[1em] items-center justify-center" 9 + > 10 + <span 11 + class="-translate-y-[0.1em] font-bold" 12 + >{{chars[index]}}</span> 13 + </div> 14 + `, 15 + changeDetection: ChangeDetectionStrategy.OnPush 16 + }) 17 + export class SpinnerComponent implements OnDestroy { 18 + chars = ['|', '/', '–', '\\']; 19 + index = 0; 20 + loop = setInterval(() => { 21 + this.index = this.index == 3 ? 0 : this.index + 1; 22 + this.cdRef.markForCheck(); 23 + }, 250); 24 + 25 + constructor( 26 + private cdRef: ChangeDetectorRef 27 + ) {} 28 + 29 + ngOnDestroy() { 30 + clearInterval(this.loop); 31 + } 32 + }