Files
angor-hub-old/src/app/components/profile/profile.component.html

669 lines
29 KiB
HTML

<div class="flex min-w-0 flex-auto flex-col">
<!-- Header -->
<div class="bg-card flex flex-col shadow">
<!-- Cover image -->
<div>
<img
class="h-40 object-cover lg:h-80"
[src]="profileUser?.banner || '/images/pages/profile/cover.jpg'"
onerror="this.onerror=null; this.src='/images/pages/profile/cover.jpg';"
alt="{{
profileUser?.display_name || profileUser?.name || 'Banner'
}}"
/>
</div>
<!-- User info -->
<div
class="bg-card mx-auto flex w-full max-w-5xl flex-0 flex-col items-center px-8 lg:h-18 lg:flex-row"
>
<!-- picture -->
<div class="-mt-26 flex-shrink-0 rounded-full lg:-mt-22">
<ng-container *ngIf="profileUser?.picture; else defaultAvatar">
<img
class="ring-bg-card h-32 min-h-32 w-32 min-w-32 max-w-fit rounded-full object-cover ring-4"
[src]="getSafeUrl(profileUser?.picture)"
onerror="this.onerror=null; this.src='/images/avatars/avatar-placeholder.png';"
alt="{{
profileUser?.display_name || profileUser?.name || ''
}}"
/>
</ng-container>
<ng-template #defaultAvatar>
<img
class="ring-bg-card h-32 min-h-32 w-32 min-w-32 rounded-full object-cover ring-4"
src="/images/avatars/avatar-placeholder.png"
onerror="this.onerror=null; this.src='/images/avatars/avatar-placeholder.png';"
alt="{{
profileUser?.display_name || profileUser?.name || ''
}}"
/>
</ng-template>
</div>
<!-- Details -->
<div
class="mt-4 flex flex-grow flex-col items-center lg:ml-8 lg:mt-0 lg:items-start"
>
<div
class="max-w-full truncate text-lg font-bold leading-tight lg:max-w-[25rem]"
style="
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
>
{{
profileUser?.display_name ||
profileUser?.name ||
'Unknown User'
}}
</div>
<div
class="text-secondary max-w-full truncate leading-tight lg:max-w-[25rem]"
style="
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
>
{{ profileUser?.username || profileUser?.name }}
</div>
</div>
<!-- Separator -->
<div class="mx-8 hidden h-8 flex-shrink-0 border-l-2 lg:flex"></div>
<div class="flex flex-shrink-0 items-center space-x-6 lg:mt-0">
<div
*ngIf="isCurrentUserProfile; else otherUserStats"
class="mt-6 flex flex-shrink-0 items-center space-x-6 lg:mt-0"
>
<ng-container *ngIf="stats$ | async as stats">
<div class="flex flex-col items-center">
<span
[matTooltip]="
'Total contact: ' + stats.totalContacts
"
class="font-bold"
>
{{ stats.followersCount }}
</span>
<span class="text-secondary text-sm font-medium"
>FOLLOWERS</span
>
</div>
<div class="flex flex-col items-center">
<span class="font-bold">{{
stats.followingCount
}}</span>
<span
[matTooltip]="
'Total contact: ' + stats.totalContacts
"
class="text-secondary text-sm font-medium"
>
FOLLOWING
</span>
</div>
</ng-container>
</div>
<ng-template #otherUserStats>
<div
class="mt-6 flex flex-shrink-0 items-center space-x-6 lg:mt-0"
>
<div class="flex flex-col items-center">
<span
[matTooltip]="'Total contact: ' + totalContacts"
class="font-bold"
>
{{ followersCount }}
</span>
<span class="text-secondary text-sm font-medium"
>FOLLOWERS</span
>
</div>
<div class="flex flex-col items-center">
<span class="font-bold">{{ followingCount }}</span>
<span
[matTooltip]="'Total contact: ' + totalContacts"
class="text-secondary text-sm font-medium"
>
FOLLOWING
</span>
</div>
</div>
</ng-template>
<!-- Separator -->
<div
class="mx-8 hidden h-8 flex-shrink-0 border-l-2 lg:flex"
></div>
<!-- Tools -->
<div
class="mb-4 mt-8 flex flex-shrink-0 items-center space-x-6 lg:m-0 lg:ml-auto"
>
<div *ngIf="!isCurrentUserProfile">
<button
mat-icon-button
(click)="toggleFollow()"
[matTooltip]="isFollowing ? 'Unfollow' : 'Follow'"
>
<mat-icon
[svgIcon]="
isFollowing
? 'heroicons_outline:user-minus'
: 'heroicons_outline:user-plus'
"
>
</mat-icon>
</button>
</div>
<div>
<button
mat-icon-button
[matMenuTriggerFor]="profileMenu"
>
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:ellipsis-vertical'"
></mat-icon>
</button>
<mat-menu #profileMenu="matMenu">
<!-- Send/Receive Zap -->
<button
mat-menu-item
(click)="openZapDialog()"
*ngIf="
!isCurrentUserProfile ||
isCurrentUserProfile
"
>
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="
isCurrentUserProfile
? 'heroicons_outline:qr-code'
: 'feather:zap'
"
></mat-icon>
<span>{{
isCurrentUserProfile
? 'Receive Zap'
: 'Send Zap'
}}</span>
</span>
</button>
<!-- Copy Keys -->
<ng-container *ngFor="let key of ['hex', 'npub']">
<button mat-menu-item (click)="copyKey(key)">
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="
'heroicons_outline:clipboard-document'
"
></mat-icon>
<span>Copy Public key ({{ key }})</span>
</span>
</button>
</ng-container>
<!-- Divider -->
<mat-divider class="my-2"></mat-divider>
<!-- Edit Profile for Current User -->
<button
*ngIf="isCurrentUserProfile"
mat-menu-item
[routerLink]="'/settings/profile'"
>
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="
'heroicons_outline:pencil-square'
"
></mat-icon>
<span>Edit your profile</span>
</span>
</button>
<!-- Report and Notifications for Other Users -->
<ng-container *ngIf="!isCurrentUserProfile">
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="
'heroicons_solid:exclamation-triangle'
"
></mat-icon>
<span>Report</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="'heroicons_solid:bell'"
></mat-icon>
<span>Turn on notifications</span>
</span>
</button>
</ng-container>
</mat-menu>
</div>
</div>
</div>
</div>
</div>
<!-- Main -->
<div class="mx-auto w-full max-w-5xl p-6 sm:p-8">
<!-- About Section -->
<!-- <mat-accordion class="mb-8 max-w-4xl w-full about-section p-6 transition-all duration-300">
<mat-expansion-panel>
<mat-expansion-panel-header
[collapsedHeight]="'56px'"
>
<mat-panel-title
class="font-medium leading-tight"
>About</mat-panel-title
>
</mat-expansion-panel-header>
{{ profileUser?.about || '' }}
</mat-expansion-panel>
</mat-accordion> -->
<!-- Main Section -->
<div class="m-auto flex w-full max-w-140 flex-col items-start">
<angor-card
*ngIf="profileUser?.about && profileUser.about.trim() !== ''"
class="about-section mb-8 flex w-full flex-col items-start p-6 pb-6 transition-all duration-300 sm:p-8"
[ngStyle]="{
height: aboutExpanded ? 'auto' : '80px',
overflow: aboutExpanded ? 'visible' : 'hidden',
}"
style="position: relative"
>
<div class="mb-2 flex w-full items-center justify-between">
<div class="text-2xl font-semibold leading-tight">
About
</div>
<button
mat-icon-button
color="primary"
(click)="toggleAbout()"
style="position: absolute; top: 16px; right: 16px"
aria-label="Toggle about section"
>
<mat-icon [svgIcon]="aboutExpanded ? 'heroicons_outline:chevron-up' : 'heroicons_outline:chevron-down'"></mat-icon>
</button>
</div>
<div
class="about-content text-base text-gray-700 dark:text-gray-50 transition-all duration-300"
[ngStyle]="{
'white-space': aboutExpanded ? 'normal' : 'nowrap',
'max-height': aboutExpanded ? 'none' : '1.5em',
overflow: 'hidden',
}"
>
{{ profileUser?.about || '' }}
<span *ngIf="!aboutExpanded" class="text-gray-500"
>...</span
>
</div>
</angor-card>
<!-- Create Post -->
<angor-card
*ngIf="isCurrentUserProfile"
class="mb-8 flex w-full flex-col p-6 pb-6 sm:p-8"
>
<div class="flex justify-between">
<div class="text-xl font-semibold">Create Post</div>
<!-- Toggle preview -->
<mat-slide-toggle
class="-mr-4 ml-auto"
[color]="'primary'"
(change)="togglePreview()"
>
Preview
</mat-slide-toggle>
</div>
<div class="mt-8 flex flex-col items-start sm:flex-row">
<mat-form-field
class="w-full"
[subscriptSizing]="'dynamic'"
>
<textarea
matInput
[placeholder]="'What\'s on your mind?'"
[rows]="3"
#eventInput
cdkTextareaAutosize
></textarea>
</mat-form-field>
</div>
<div
class="-mx-3 mt-6 flex items-center justify-between sm:mt-8"
>
<div class="flex items-center">
<button
class="mr-1 px-3"
mat-button
(click)="toggleEmojiPicker()"
>
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:face-smile'"
></mat-icon>
<span class="ml-2">Feeling</span>
</button>
<div
*ngIf="showEmojiPicker"
class="emoji-picker-container-global"
>
<emoji-mart
(emojiClick)="addEmoji($event)"
[darkMode]="darkMode"
></emoji-mart>
</div>
<button
class="mr-1 hidden px-3 sm:inline-flex"
mat-button
>
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:photo'"
></mat-icon>
<span class="ml-2">Media</span>
</button>
<button
class="mr-1 hidden px-3 sm:inline-flex"
mat-button
>
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:user-circle'"
></mat-icon>
<span class="ml-2">Tag</span>
</button>
<button
class="px-3"
mat-button
[matMenuTriggerFor]="postCardMenu01"
>
<mat-icon
class="icon-size-5"
[svgIcon]="
'heroicons_solid:ellipsis-horizontal'
"
></mat-icon>
</button>
<mat-menu #postCardMenu01="matMenu">
<button class="sm:hidden" mat-menu-item>
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="
'heroicons_solid:user-circle'
"
></mat-icon>
<span>Tag</span>
</span>
</button>
<button class="sm:hidden" mat-menu-item>
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="'heroicons_solid:face-smile'"
></mat-icon>
<span>Feeling</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="'heroicons_solid:play'"
></mat-icon>
<span>Live</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="'heroicons_solid:sparkles'"
></mat-icon>
<span>Gif</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="mr-3 icon-size-5"
[svgIcon]="'heroicons_solid:map-pin'"
></mat-icon>
<span>Check in</span>
</span>
</button>
</mat-menu>
</div>
<button
class="mr-1 flex px-3"
mat-button
(click)="sendEvent()"
>
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:paper-airplane'"
></mat-icon>
<span class="ml-2">Send</span>
</button>
</div>
</angor-card>
<!-- preview -->
<angor-card
*ngIf="isPreview"
class="mb-8 flex w-full flex-col bg-primary-50 dark:bg-primary-800"
#expandableComments="angorCard"
>
<div class="mx-6 mb-4 mt-6 flex items-center sm:mx-8">
<img
class="mr-4 h-10 w-10 rounded-full object-cover"
[src]="getSafeUrl(profileUser?.picture)"
onerror="this.onerror=null; this.src='/images/avatars/avatar-placeholder.png';"
alt="{{
profileUser?.display_name || profileUser?.name || ''
}}"
/>
<div class="flex flex-col">
<span class="font-semibold leading-none">{{
profileUser?.display_name || profileUser?.name || ''
}}</span>
<span class="text-secondary mt-1 text-sm leading-none"
>1 minutes ago</span
>
</div>
</div>
<div
*ngFor="
let token of parseContent.parseContent(
eventInput.nativeElement.value
);
trackBy: trackByFn
"
class="inline-block whitespace-pre-wrap break-words"
>
<!-- YouTube Embeds -->
<!-- <ng-container *ngIf="token.token === 'youtube'">
<div class="relative mb-4 block">
<iframe [src]="token.safeWord" width="560" height="315" frameborder="0"
allowfullscreen></iframe>
</div>
</ng-container> -->
<!-- Images -->
<ng-container *ngIf="token.token === 'image'">
<div class="relative mb-4 block">
<img
[src]="token.safeWord"
alt="Embedded Image"
style="width: 100%"
class="max-h-140 object-cover"
/>
</div>
</ng-container>
<!-- Videos -->
<ng-container *ngIf="token.token === 'video'">
<div class="relative mb-4 block">
<video controls style="width: 100%">
<source
[src]="token.safeWord"
type="video/mp4"
/>
Your browser does not support the video tag.
</video>
</div>
</ng-container>
<!-- Audio -->
<ng-container *ngIf="token.token === 'audio'">
<div class="relative mb-4 block">
<audio controls>
<source
[src]="token.safeWord"
type="audio/mpeg"
/>
Your browser does not support the audio element.
</audio>
</div>
</ng-container>
<!-- Links -->
<ng-container *ngIf="token.token === 'link'">
<div class="mx-6 mb-6 mt-2 sm:mx-8">
<a
class="inline-block break-words text-blue-500 underline"
[href]="token.word"
target="_blank"
>
<span
class="inline-block break-words"
>{{ token.word }}</span
>
</a>
</div>
</ng-container>
<!-- Plain Text -->
<ng-container *ngIf="!token.token">
<div class="mx-6 mb-6 mt-2 sm:mx-8">
<span
class="inline-block break-words"
[ngClass]="{
'large-font': isSingleEmojiOrWord(token),
}"
>
{{ token.trim() }}
</span>
</div>
</ng-container>
</div>
<div class="mx-3 flex items-center sm:mx-5">
<button class="mr-1 px-3" mat-button>
<mat-icon
class="text-red-500 icon-size-5"
[svgIcon]="'heroicons_solid:heart'"
></mat-icon>
<span class="ml-2">Unlike</span>
</button>
<button class="mr-1 px-3" mat-button>
<mat-icon
class="text-blue-500 icon-size-5"
[svgIcon]="
'heroicons_solid:chat-bubble-left-ellipsis'
"
></mat-icon>
<span class="ml-2">Comment</span>
</button>
<button class="mr-1 px-3" mat-button>
<mat-icon
class="text-green-500 icon-size-5"
[svgIcon]="'heroicons_solid:share'"
></mat-icon>
<span class="ml-2">Share</span>
</button>
<button class="mr-1 px-3" mat-button>
<mat-icon
class="text-orange-500 icon-size-5"
[svgIcon]="'heroicons_solid:bolt'"
></mat-icon>
<span class="ml-2">Zap</span>
</button>
</div>
<hr class="mx-6 mb-6 mt-4 border-b sm:mx-8" />
<div
class="mx-6 mb-4 flex flex-col sm:mx-8 sm:mb-6 sm:flex-row sm:items-center"
>
<div class="flex items-center">
<div class="ml-3 text-md tracking-tight">0 Zap</div>
</div>
<div class="hidden flex-auto sm:flex"></div>
<div class="mt-4 flex items-center sm:mt-0">
<button class="-ml-2 mr-1 px-3 sm:ml-0" mat-button>
0 Like
</button>
<button class="-ml-2 mr-1 px-3 sm:ml-0" mat-button>
0 shares
</button>
<button class="px-3 sm:-mr-4" mat-button>
<span class="mr-1">0 Comments</span>
</button>
</div>
</div>
</angor-card>
@for (item of posts; track $index) {
<app-post
class="mb-8 flex w-full flex-col"
[item]="item"
></app-post>
}
@if (hasMorePosts) {
<div class="m-auto mt-4 flex justify-center">
<button
class="bg-card text-gray-700 hover:bg-gray-200 dark:text-gray-300 dark:hover:bg-gray-700"
mat-raised-button
color="primary"
(click)="loadNextPage()"
[disabled]="loading"
>
{{ loading ? 'Loading...' : 'Load More Posts' }}
</button>
</div>
}
</div>
</div>
</div>