Feature/profile banner (#51)

* Add profile banner rendering

* Fix thread rendering issue
This commit is contained in:
SondreB 2023-01-15 03:32:20 +01:00 committed by GitHub
parent 9bdc5f3968
commit bc7353c976
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 112 additions and 37 deletions

View File

@ -92,7 +92,7 @@ export class PeopleComponent {
}
async ngOnInit() {
this.appState.title = 'People';
this.appState.updateTitle('People');
this.appState.showBackButton = false;
this.appState.actions = [
{

View File

@ -47,7 +47,7 @@ export class ProfileComponent {
) {}
async ngOnInit() {
this.appState.title = 'Edit Profile';
this.appState.updateTitle('Edit Profile');
this.originalProfile = {
name: '',

View File

@ -144,13 +144,51 @@ export class Utilities {
return secp.utils.bytesToHex(publicKey);
}
sanitize(url: string) {
sanitizeLUD06(url?: string) {
// Do not allow http prefix.
if (!url && url?.startsWith('http')) {
return undefined;
}
return url;
}
sanitizeUrl(url?: string) {
if (!url && !url?.startsWith('http')) {
return '';
}
return url;
}
sanitizeImageUrl(url?: string) {
url = this.sanitizeUrl(url);
if (!url) {
return undefined;
}
const urlLower = url.toLowerCase();
if (urlLower.endsWith('jpg') || urlLower.endsWith('jpeg') || urlLower.endsWith('png') || urlLower.endsWith('webp') || urlLower.endsWith('gif')) {
return url;
}
return undefined;
}
bypassUrl(url: string) {
const clean = this.sanitizer.bypassSecurityTrustUrl(url);
return clean;
}
sanitizeUrl(url: string) {
bypassResourceUrl(url: string) {
const clean = this.sanitizer.bypassSecurityTrustResourceUrl(url);
return clean;
}
bypassStyle(url: string) {
const clean = this.sanitizer.bypassSecurityTrustStyle(url);
return clean;
}
}

View File

@ -75,7 +75,7 @@ export class ContentComponent {
this.images = images.map((i) => this.utilities.sanitizeUrl(i[0]));
const thisisthewayMatch = [...content.matchAll(ContentComponent.regexpThisIsTheWay)];
const thisistheway = thisisthewayMatch.map((i) => this.utilities.sanitizeUrl(`https://i.ytimg.com/vi/LaiN63o_BxA/maxresdefault.jpg`));
const thisistheway = thisisthewayMatch.map((i) => this.utilities.bypassResourceUrl(`https://i.ytimg.com/vi/LaiN63o_BxA/maxresdefault.jpg`));
this.images.push(...thisistheway);
const videos = [...content.matchAll(ContentComponent.regexpVideo)];

View File

@ -81,3 +81,13 @@
width: 100%;
height: 100%;
}
.profile-banner {
background-repeat: no-repeat;
background-position: center;
background-size: cover;
min-height: 240px;
/* margin-bottom: 30em;
position: fixed; */
width: 100%;
}

View File

@ -1,24 +1,24 @@
<div class="profile-page">
<div class="profile-page-header" *ngIf="ui.profile$ | async as profile">
<div class="profile-page" *ngIf="ui.profile$ | async as profile">
<div [style.background-image]="getBannerBackgroundStyle(profile.banner)" class="profile-banner"></div>
<div class="profile-page-header">
<!-- <img [src]="profile.banner"> -->
<div class="profile-page-header-left">
<img *ngIf="profile?.status == 1" (click)="showProfileImage()" class="profile-image-large profile-image-follow" [style.borderColor]="circleService.getSync(profile.circle)?.color" [src]="imagePath" />
<img *ngIf="profile?.status != 1" (click)="showProfileImage()" class="profile-image-large profile-image-follow" matTooltipPosition="above" [src]="imagePath" />
<div id="profile-image-anchor" class="profile-image-anchor">
<img id="profile-image" *ngIf="profile?.status == 1" (click)="showProfileImage()" class="profile-image-large profile-image-follow" [style.borderColor]="circleService.getSync(profile.circle)?.color" [src]="imagePath" />
<img id="profile-image" *ngIf="profile?.status != 1" (click)="showProfileImage()" class="profile-image-large profile-image-follow" matTooltipPosition="above" [src]="imagePath" />
</div>
</div>
<div class="profile-page-header-middle">
<div class="profile-button-container">
<app-profile-actions [showFollow]="true" [fab]="false" [profile]="profile"></app-profile-actions>
</div>
<h2 class="profile-name" [matTooltip]="npub" matTooltipPosition="above">
<span *ngIf="profile.display_name">
{{ profile.display_name }}
</span>
<span *ngIf="profile.display_name"> {{ profile.display_name }} </span>
<span *ngIf="!profile.display_name">
<span *ngIf="profile.name">
{{ profile.name }}
</span>
<span *ngIf="!profile.display_name && !profile.name">
{{ profile.npub }}
</span>
<span *ngIf="profile.name"> {{ profile.name }} </span>
<span *ngIf="!profile.display_name && !profile.name"> {{ profile.npub }} </span>
</span>
</h2>
<div class="profile-labels">
@ -38,7 +38,7 @@
<div class="profile-labels" *ngIf="profile.website">
<div class="profile-labels-left"><mat-icon class="profile-icon">link</mat-icon></div>
<div class="profile-labels-middle dimmed">
<a class="dimmed lightning-link hoverable" *ngIf="profile.website" [href]="utilities.sanitize(profile.website)" target="_blank">{{ profile.website }}</a>
<a class="dimmed lightning-link hoverable" *ngIf="profile.website" [href]="utilities.sanitizeUrl(profile.website)" target="_blank">{{ profile.website }}</a>
</div>
<!-- <div class="profile-labels-right"></div> -->
</div>
@ -46,7 +46,7 @@
<div class="profile-labels-left"><mat-icon class="profile-icon-custom">⚡️</mat-icon></div>
<div class="profile-labels-middle dimmed">
<!-- <a class="dimmed lightning-link" (click)="toggleLn()" *ngIf="profile.lud16 && paymentVersion == 'lud16'" [href]="utilities.sanitize('lightning:' + profile.lud16)">{{ profile.lud16 }}</a> -->
<a class="dimmed lightning-link hoverable" *ngIf="profile.lud06 && paymentVersion == 'lud06'" [href]="utilities.sanitize('lightning:' + profile.lud06)">{{ getLightningLabel(profile.lud06) }}</a>
<a class="dimmed lightning-link hoverable" *ngIf="profile.lud06 && paymentVersion == 'lud06'" [href]="utilities.sanitizeLUD06('lightning:' + profile.lud06)">{{ getLightningLabel(profile.lud06) }}</a>
</div>
<!-- <div class="profile-labels-right"></div> -->
</div>

View File

@ -46,6 +46,16 @@ export class ProfileHeaderComponent {
return ProfileHeaderComponent.defaultProfileImage;
}
getBannerBackgroundStyle(banner?: string) {
if (!banner) {
return 'url(https://dafb3cv85j5xj.cloudfront.net/blog/wp-content/uploads/2017/04/journey.gif)';
}
return `url(${banner})`;
// return this.utilities.sanitizeStyleUrl(banner);
}
showProfileImage() {
this.dialog.open(ProfileImageDialog, {
data: { picture: this.imagePath },

View File

@ -2,3 +2,6 @@
display: inline-block;
}
.feed-page {
min-height: 1200px;
}

View File

@ -155,10 +155,20 @@ export class UserComponent {
this.queueService.enqueContacts(profile.pubkey);
// this.downloadFollowingAndRelays(profile);
}
if (this.previousPubKey != profile.pubkey) {
setTimeout(() => {
const element2 = document.getElementById('profile-image-anchor');
element2!.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' });
this.previousPubKey = profile.pubkey;
}, 50);
}
})
);
}
previousPubKey?: string;
async follow() {
this.ui.profile!.status = ProfileStatus.Follow;
await this.profiles.follow(this.ui.pubkey);

View File

@ -131,7 +131,7 @@ h3 {
}
.profile-page {
padding: 1.6em 1.6em 0 1.6em;
// padding: 1.6em 1.6em 0 1.6em;
}
.feed-page {
@ -146,9 +146,6 @@ h3 {
border-left: 2px solid rgba(255, 255, 255, 0.15) !important;
}
.image-grid {
display: grid;
gap: 8px;
@ -177,18 +174,6 @@ h3 {
width: 100%;
}
/* When changing the sidenav-content to flex, the toolbar does not render properly, so a minor hack is needed. */
@media only screen and (max-width: 599px) {
body {
@ -200,7 +185,11 @@ h3 {
}
.profile-page {
padding: 0.8em 0.8em 0 0.8em;
// padding: 0.8em 0.8em 0 0.8em;
}
.profile-page-header {
padding: 0 0.8em 0 0.8em;
}
.feed-page {
@ -422,6 +411,8 @@ mat-sidenav-content mat-toolbar {
}
.profile-image {
// padding-top: 3em;
// margin-top: 3em;
/* border: 1px solid; */
}
@ -434,12 +425,19 @@ mat-sidenav-content mat-toolbar {
}
.profile-page-header {
padding: 0 1.6em 0 1.6em;
display: flex;
gap: 1em;
}
.profile-page-header-left {
flex: 0 1 auto;
// display: flex;
}
.profile-image-anchor {
padding-top: 1.4em;
margin-top: -6em;
}
.profile-page-header-middle {
@ -495,6 +493,7 @@ mat-sidenav-content mat-toolbar {
width: 150px;
height: 150px;
border-radius: 50%;
// margin-top: -3em;
}
.profile-image-large:hover {
@ -508,6 +507,11 @@ mat-sidenav-content mat-toolbar {
height: 96px;
border-radius: 50%;
}
.profile-image-anchor {
padding-top: 1em;
margin-top: -4em;
}
}
.event-header .name {