From 0e545e21216b2e764a5039abd2034a8d51863469 Mon Sep 17 00:00:00 2001 From: Robinson Zimmermann <16561945+robinsonzimmermann@users.noreply.github.com> Date: Thu, 2 May 2024 16:12:01 +0200 Subject: [PATCH] Feature/improve image processing (#117) * Keep only generated images in production * Remove necessity of processing images on local --- angular.json | 23 +++++- .../post.md | 4 +- package.json | 2 +- src/app/app.config.ts | 10 ++- .../components/author/author.component.html | 6 +- .../components/author/author.component.scss | 8 --- src/app/components/author/author.component.ts | 14 ++-- .../components/avatar/avatar.component.html | 47 ++++++++++-- .../components/avatar/avatar.component.scss | 55 ++++++++------ src/app/components/avatar/avatar.component.ts | 25 +++++-- .../post-featured.component.html | 5 +- .../post-featured.component.scss | 3 +- .../post-image/post-image.component.html | 18 ++--- .../post-image/post-image.component.ts | 21 +----- .../post-item/post-item.component.html | 4 +- src/app/core/config/configuration-tokens.ts | 4 ++ src/app/core/model/author.model.ts | 3 + src/app/core/model/content.model.ts | 4 ++ src/app/core/model/post.model.ts | 2 + src/app/core/services/assets.service.spec.ts | 16 +++++ src/app/core/services/assets.service.ts | 19 +++++ src/app/core/services/authors.service.ts | 38 +++++++--- .../core/services/html-in-markdown.service.ts | 4 ++ src/app/core/services/posts.service.ts | 17 ++++- src/app/features/author/author.component.html | 2 +- src/app/features/author/author.component.scss | 5 ++ .../features/authors/authors.component.html | 2 +- src/app/features/post/post.component.scss | 2 +- src/app/markdown.config.ts | 71 +++++++++---------- tools/process-images/index.js | 1 + 30 files changed, 302 insertions(+), 133 deletions(-) create mode 100644 src/app/core/services/assets.service.spec.ts create mode 100644 src/app/core/services/assets.service.ts diff --git a/angular.json b/angular.json index c2a40a50..729f5023 100644 --- a/angular.json +++ b/angular.json @@ -28,7 +28,7 @@ "src/assets", { "glob": "**/*.*", - "input": "content/authors/avatars/dist", + "input": "content/authors/avatars", "output": "/authors" }, { @@ -79,6 +79,27 @@ "maximumError": "6kb" } ], + "assets": [ + "src/favicon.ico", + "src/assets", + { + "glob": "**/*.*", + "input": "content/authors/avatars", + "output": "/authors", + "ignore": ["*.*"] + }, + { + "glob": "**/*.*", + "input": "content/posts", + "output": "/", + "ignore": ["**/assets/*.*"] + }, + { + "glob": "authors.json", + "input": "content/authors", + "output": "/" + } + ], "outputHashing": "all" }, "development": { diff --git a/content/posts/2020/03/04/kubernetes-application-developer-certification-tips/post.md b/content/posts/2020/03/04/kubernetes-application-developer-certification-tips/post.md index 84245657..20ad4897 100644 --- a/content/posts/2020/03/04/kubernetes-application-developer-certification-tips/post.md +++ b/content/posts/2020/03/04/kubernetes-application-developer-certification-tips/post.md @@ -24,9 +24,9 @@ First, you need a base, if you have no work experience with production Kubernete Here some nice intros: -![The illustrated Children’s Guide to Kubernetes](https://www.youtube.com/embed/4ht22ReBjno) + -![Kubernetes explained](https://www.youtube.com/embed/aSrqRSk43lY) + For something more academic I would recommend following the course: diff --git a/package.json b/package.json index 492af076..bd506be7 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "scripts": { "ng": "ng", - "prestart": "npm run posts:update && npm run images:authors && npm run images:posts && npm run build:utils", + "prestart": "npm run posts:update && npm run build:utils", "start": "ng serve", "prebuild": "npm run posts:update && npm run images:authors && npm run images:posts", "build": "ng build", diff --git a/src/app/app.config.ts b/src/app/app.config.ts index b8081fd8..f9cf5e14 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -3,6 +3,7 @@ import { ApplicationConfig, SecurityContext, importProvidersFrom, + isDevMode, } from '@angular/core'; import { provideRouter, withInMemoryScrolling } from '@angular/router'; @@ -13,8 +14,9 @@ import { MarkdownModule, MarkdownService } from 'ngx-markdown'; import { HttpClient, provideHttpClient, withFetch } from '@angular/common/http'; import markdownConfig from './markdown.config'; import { DOCUMENT } from '@angular/common'; -import { AUTHORS_AVATAR_PATH_TOKEN } from './core/config/configuration-tokens'; import { HtmlInMarkdownService } from './core/services/html-in-markdown.service'; +import { AssetsService } from './core/services/assets.service'; +import { AUTHORS_AVATAR_PATH_TOKEN, USE_PROCESSED_IMAGES } from './core/config/configuration-tokens'; export const appConfig: ApplicationConfig = { providers: [ @@ -37,11 +39,15 @@ export const appConfig: ApplicationConfig = { { provide: APP_INITIALIZER, useFactory: markdownConfig, - deps: [MarkdownService, DOCUMENT, HtmlInMarkdownService], + deps: [MarkdownService, DOCUMENT, HtmlInMarkdownService, AssetsService], }, { provide: AUTHORS_AVATAR_PATH_TOKEN, useValue: 'authors', }, + { + provide: USE_PROCESSED_IMAGES, + useValue: !isDevMode(), + } ], }; diff --git a/src/app/components/author/author.component.html b/src/app/components/author/author.component.html index 390b039b..997d3ebb 100644 --- a/src/app/components/author/author.component.html +++ b/src/app/components/author/author.component.html @@ -7,9 +7,11 @@ lg: size === 'lg', muted: muted }"> -
+ [url]="author.displayAvatar?.[size]" + format="circle" + >
{{ author.fullname }}
@if (size === 'lg') { diff --git a/src/app/components/author/author.component.scss b/src/app/components/author/author.component.scss index 39e1bfd7..81e5298f 100644 --- a/src/app/components/author/author.component.scss +++ b/src/app/components/author/author.component.scss @@ -11,14 +11,6 @@ &__avatar { width: 1.2rem; height: 1.2rem; - min-width: 1.2rem; - border-radius: 100rem; - background-size: cover; - background-position: center; - - img { - width: 100%; - } } &__fullname { font-weight: 500; diff --git a/src/app/components/author/author.component.ts b/src/app/components/author/author.component.ts index b066c5af..643d3190 100644 --- a/src/app/components/author/author.component.ts +++ b/src/app/components/author/author.component.ts @@ -1,13 +1,14 @@ -import { Component, Inject, Input } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { Author } from '../../core/model/author.model'; import { NgClass, NgStyle } from '@angular/common'; -import { AUTHORS_AVATAR_PATH_TOKEN } from '../../core/config/configuration-tokens'; import { RouterLink } from '@angular/router'; +import { ImageSize } from '../../core/model/content.model'; +import { AvatarComponent } from '../avatar/avatar.component'; @Component({ selector: 'blog-author', standalone: true, - imports: [NgStyle, NgClass, RouterLink], + imports: [NgStyle, NgClass, RouterLink, AvatarComponent], templateUrl: './author.component.html', styleUrl: './author.component.scss', }) @@ -24,14 +25,9 @@ export class AuthorComponent { this.author = value; } } - @Input() size: string = 'sm'; + @Input() size: ImageSize = 'sm'; @Input() muted = false; author!: Author; - get imagePath() { - return `${this.basePath}/${this.size}/${this.author.avatar}`; - } - - constructor(@Inject(AUTHORS_AVATAR_PATH_TOKEN) protected basePath: string) {} } diff --git a/src/app/components/avatar/avatar.component.html b/src/app/components/avatar/avatar.component.html index 0aa9d9c8..d78edcbd 100644 --- a/src/app/components/avatar/avatar.component.html +++ b/src/app/components/avatar/avatar.component.html @@ -1,4 +1,43 @@ -avatar +
+ @if (placeholder) { + + + + + + + + + + + + + + + + } @else { + avatar + } +
diff --git a/src/app/components/avatar/avatar.component.scss b/src/app/components/avatar/avatar.component.scss index ced08760..219cd8bf 100644 --- a/src/app/components/avatar/avatar.component.scss +++ b/src/app/components/avatar/avatar.component.scss @@ -1,28 +1,43 @@ -:host { - aspect-ratio: 1; +.avatar { position: relative; line-height: 1; - margin-right: 1rem; - margin-bottom: 1rem; + display: inline-flex; + width: 100%; + height: 100%; + + &__circle { + img, svg, &::before { + border-radius: 100rem; + } + } - &::before { - content: ''; - background: repeating-linear-gradient( - 55deg, - var(--blog-palette-accent), - var(--blog-palette-accent) 5px, - transparent 5px, - transparent 10px - ); - position: absolute; - height: 100%; - width: 100%; - top: 0; - left: 0; - transform: translate(1rem, 1rem); + &__shadow { + &::before { + content: ''; + background: repeating-linear-gradient( + 55deg, + var(--blog-palette-accent), + var(--blog-palette-accent) 5px, + transparent 5px, + transparent 10px + ); + position: absolute; + height: 100%; + width: 100%; + top: 0; + left: 0; + transform: translate(8%, 8%); + } } - img { + img, svg { position: relative; + background: var(--blog-palette-neutral); + width: 100%; + height: 100%; + } + + svg > * { + opacity: .5; } } diff --git a/src/app/components/avatar/avatar.component.ts b/src/app/components/avatar/avatar.component.ts index 3faf811f..42816da2 100644 --- a/src/app/components/avatar/avatar.component.ts +++ b/src/app/components/avatar/avatar.component.ts @@ -1,13 +1,28 @@ -import { Component, Input } from '@angular/core'; -import { CommonModule } from '@angular/common'; +import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core'; +import { NgClass } from '@angular/common'; @Component({ selector: 'blog-avatar', standalone: true, - imports: [CommonModule], + imports: [NgClass], templateUrl: './avatar.component.html', styleUrl: './avatar.component.scss', }) -export class AvatarComponent { - @Input() url: string | null = null; +export class AvatarComponent implements AfterViewInit { + + @Input() url!: string | undefined; + @Input() format: 'circle' | 'square' = 'circle'; + @Input() shadow = false; + + @ViewChild('avatar') + image!: ElementRef; + + placeholder: boolean = false; + + ngAfterViewInit(): void { + this.image?.nativeElement?.addEventListener('error', () => { + this.placeholder = true + }); + } + } diff --git a/src/app/components/post-featured/post-featured.component.html b/src/app/components/post-featured/post-featured.component.html index 08dbf0ba..222c5952 100644 --- a/src/app/components/post-featured/post-featured.component.html +++ b/src/app/components/post-featured/post-featured.component.html @@ -3,7 +3,10 @@ data-role="button" [routerLink]="post | postUrl"> - +