Skip to content

Commit 0e545e2

Browse files
Feature/improve image processing (#117)
* Keep only generated images in production * Remove necessity of processing images on local
1 parent 17080e0 commit 0e545e2

30 files changed

+302
-133
lines changed

angular.json

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"src/assets",
2929
{
3030
"glob": "**/*.*",
31-
"input": "content/authors/avatars/dist",
31+
"input": "content/authors/avatars",
3232
"output": "/authors"
3333
},
3434
{
@@ -79,6 +79,27 @@
7979
"maximumError": "6kb"
8080
}
8181
],
82+
"assets": [
83+
"src/favicon.ico",
84+
"src/assets",
85+
{
86+
"glob": "**/*.*",
87+
"input": "content/authors/avatars",
88+
"output": "/authors",
89+
"ignore": ["*.*"]
90+
},
91+
{
92+
"glob": "**/*.*",
93+
"input": "content/posts",
94+
"output": "/",
95+
"ignore": ["**/assets/*.*"]
96+
},
97+
{
98+
"glob": "authors.json",
99+
"input": "content/authors",
100+
"output": "/"
101+
}
102+
],
82103
"outputHashing": "all"
83104
},
84105
"development": {

content/posts/2020/03/04/kubernetes-application-developer-certification-tips/post.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ First, you need a base, if you have no work experience with production Kubernete
2424

2525
Here some nice intros:
2626

27-
![The illustrated Children’s Guide to Kubernetes](https://www.youtube.com/embed/4ht22ReBjno)
27+
<iframe width="560" height="315" src="https://www.youtube.com/embed/4ht22ReBjno?si=2oahPZeHL9Ae8N5m" title="The illustrated Children’s Guide to Kubernetes" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
2828

29-
![Kubernetes explained](https://www.youtube.com/embed/aSrqRSk43lY)
29+
<iframe width="560" height="315" src="https://www.youtube.com/embed/aSrqRSk43lY?si=PDEbpNpT_9ZwonKp" title="Kubernetes explained" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
3030

3131
For something more academic I would recommend following the course:
3232

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.0.0",
44
"scripts": {
55
"ng": "ng",
6-
"prestart": "npm run posts:update && npm run images:authors && npm run images:posts && npm run build:utils",
6+
"prestart": "npm run posts:update && npm run build:utils",
77
"start": "ng serve",
88
"prebuild": "npm run posts:update && npm run images:authors && npm run images:posts",
99
"build": "ng build",

src/app/app.config.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
ApplicationConfig,
44
SecurityContext,
55
importProvidersFrom,
6+
isDevMode,
67
} from '@angular/core';
78
import { provideRouter, withInMemoryScrolling } from '@angular/router';
89

@@ -13,8 +14,9 @@ import { MarkdownModule, MarkdownService } from 'ngx-markdown';
1314
import { HttpClient, provideHttpClient, withFetch } from '@angular/common/http';
1415
import markdownConfig from './markdown.config';
1516
import { DOCUMENT } from '@angular/common';
16-
import { AUTHORS_AVATAR_PATH_TOKEN } from './core/config/configuration-tokens';
1717
import { HtmlInMarkdownService } from './core/services/html-in-markdown.service';
18+
import { AssetsService } from './core/services/assets.service';
19+
import { AUTHORS_AVATAR_PATH_TOKEN, USE_PROCESSED_IMAGES } from './core/config/configuration-tokens';
1820

1921
export const appConfig: ApplicationConfig = {
2022
providers: [
@@ -37,11 +39,15 @@ export const appConfig: ApplicationConfig = {
3739
{
3840
provide: APP_INITIALIZER,
3941
useFactory: markdownConfig,
40-
deps: [MarkdownService, DOCUMENT, HtmlInMarkdownService],
42+
deps: [MarkdownService, DOCUMENT, HtmlInMarkdownService, AssetsService],
4143
},
4244
{
4345
provide: AUTHORS_AVATAR_PATH_TOKEN,
4446
useValue: 'authors',
4547
},
48+
{
49+
provide: USE_PROCESSED_IMAGES,
50+
useValue: !isDevMode(),
51+
}
4652
],
4753
};

src/app/components/author/author.component.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
lg: size === 'lg',
88
muted: muted
99
}">
10-
<div
10+
<blog-avatar
1111
class="author__avatar"
12-
[ngStyle]="{ 'background-image': 'url(' + imagePath + ')' }"></div>
12+
[url]="author.displayAvatar?.[size]"
13+
format="circle"
14+
></blog-avatar>
1315
<div class="author__details">
1416
<div class="author__fullname">{{ author.fullname }}</div>
1517
@if (size === 'lg') {

src/app/components/author/author.component.scss

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,6 @@
1111
&__avatar {
1212
width: 1.2rem;
1313
height: 1.2rem;
14-
min-width: 1.2rem;
15-
border-radius: 100rem;
16-
background-size: cover;
17-
background-position: center;
18-
19-
img {
20-
width: 100%;
21-
}
2214
}
2315
&__fullname {
2416
font-weight: 500;
Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { Component, Inject, Input } from '@angular/core';
1+
import { Component, Input } from '@angular/core';
22
import { Author } from '../../core/model/author.model';
33
import { NgClass, NgStyle } from '@angular/common';
4-
import { AUTHORS_AVATAR_PATH_TOKEN } from '../../core/config/configuration-tokens';
54
import { RouterLink } from '@angular/router';
5+
import { ImageSize } from '../../core/model/content.model';
6+
import { AvatarComponent } from '../avatar/avatar.component';
67

78
@Component({
89
selector: 'blog-author',
910
standalone: true,
10-
imports: [NgStyle, NgClass, RouterLink],
11+
imports: [NgStyle, NgClass, RouterLink, AvatarComponent],
1112
templateUrl: './author.component.html',
1213
styleUrl: './author.component.scss',
1314
})
@@ -24,14 +25,9 @@ export class AuthorComponent {
2425
this.author = value;
2526
}
2627
}
27-
@Input() size: string = 'sm';
28+
@Input() size: ImageSize = 'sm';
2829
@Input() muted = false;
2930

3031
author!: Author;
3132

32-
get imagePath() {
33-
return `${this.basePath}/${this.size}/${this.author.avatar}`;
34-
}
35-
36-
constructor(@Inject(AUTHORS_AVATAR_PATH_TOKEN) protected basePath: string) {}
3733
}
Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,43 @@
1-
<img
2-
[src]="'authors/lg/' + url"
3-
onerror="this.src='authors/lg/placeholder.jpg'"
4-
alt="avatar" />
1+
<div class="avatar avatar__{{format}}" [ngClass]="{ 'avatar__shadow': shadow }">
2+
@if (placeholder) {
3+
<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" width="483" height="483"
4+
viewBox="0 0 878.63037 483" xmlns:xlink="http://www.w3.org/1999/xlink">
5+
<g>
6+
<circle id="fff0188c-9915-4c0d-8339-9317a77083e8" data-name="Ellipse 276" cx="441.8526"
7+
cy="99.21067" r="70.6659" fill="#DDDEE0" />
8+
<path id="ac220ed6-7c3f-4d1e-8d82-3295770c496a-5146" data-name="Path 1461"
9+
d="M668.54008,246.746a81.61376,81.61376,0,0,0-46.43-35.49166l-8.6754,6.33079v-8.22035a75.12281,75.12281,0,0,0-14.03207-.81741l-7.48468,6.7722V209.11a80.83444,80.83444,0,0,0-55.76328,33.16889c-16.25407,23.43225-18.99783,56.03165-3.01076,79.65191,4.38811-13.48715,9.71486-26.14193,14.1043-39.62775a39.91571,39.91571,0,0,0,10.39873.05039l5.339-12.45857,1.49177,11.93136c16.54971-1.44138,41.0963-4.60742,56.785-7.50784l-1.52581-9.15355,9.12769,7.606c4.80635-1.10624,7.66041-2.11028,7.42476-2.87726,11.66844,18.81119,25.94847,30.82566,37.61558,49.63682C678.33663,293.0056,683.43725,270.95065,668.54008,246.746Z"
10+
transform="translate(-160.68481 -208.5)" fill="#919294" />
11+
<path
12+
d="M754.51974,489.43043c-2.43-14.61929-4.93649-29.51921-11.73089-42.68893-4.46552-8.62629-11.55394-16.84664-21.1096-18.55231a20.4215,20.4215,0,0,1-5.49659-1.27245c-2.79985-1.34871-40.42516-22.82733-46.40535-26.56828-5.13471-3.21152-13.24023-9.158-17.32725-9.158-4.11163-.09038-19.87765,3.579-81.41374-1.23129,0,0-16.90485,6.66319-29.98543,14.74285-.19823-.13063-63.869,34.06031-66.261,33.97034-4.53005-.19075-8.74079,2.70971-11.33775,6.36219-2.5963,3.65239-3.81429,8.174-5.08948,12.54576,13.90677,30.97,26.6308,61.97961,40.5389,92.94963a7.93068,7.93068,0,0,1,1.00579,3.81454,9.30964,9.30964,0,0,1-1.7302,3.81453c-6.82034,10.95592-6.60348,24.736-5.85845,37.61284.74569,12.87686,1.66766,26.47839-4.087,38.02019-1.56523,3.16878-3.60075,6.06924-5.08948,9.238-3.48634,7.17681-4.74624,30.13086-2.71,37.84166l255.12065,7.30869C730.06748,673.1021,754.51974,489.43043,754.51974,489.43043Z"
13+
transform="translate(-160.68481 -208.5)" fill="#AEAFB0" />
14+
<path id="bb46eb08-8e3e-4ac5-913b-26d221d967b9-5147" data-name="Path 1421"
15+
d="M436.31023,551.90313a45.04293,45.04293,0,0,0-.15258,11.10851l3.65653,52.51275c.34331,4.94938.68117,9.88653,1.14573,14.82359.87734,9.58136,2.18792,19.08639,3.81455,28.57778a5.08966,5.08966,0,0,0,5.21639,4.94937c16.096,3.40585,32.72612,3.26965,49.15321,2.34185,25.067-1.39909,89.1978-4.0461,93.11589-9.13583s1.63483-13.32231-3.474-17.43793-89.73865-14.14932-89.73865-14.14932c.82693-6.55285,3.32139-12.72429,5.68777-18.946,4.25049-11.03491,8.22035-22.43228,8.29664-34.2533s-4.37719-24.24962-14.0607-31.02182c-7.9656-5.5597-18.22129-6.591-27.928-6.3621-7.06238.203-19.26485-1.48907-25.71553,1.27245C440.22288,538.431,437.26387,546.90479,436.31023,551.90313Z"
16+
transform="translate(-160.68481 -208.5)" fill="#DFE0E2" />
17+
<path id="efe93a1e-ccdd-49fd-af5f-e26394aa0937-5148" data-name="Path 1430"
18+
d="M457.62676,458.523a13.16962,13.16962,0,0,0-2.82413,4.51753A213.58786,213.58786,0,0,0,436.862,536.35613a7.32926,7.32926,0,0,1-.82693,3.55028,15.53466,15.53466,0,0,1-1.87049,2.023,7.02422,7.02422,0,0,0,.84,9.89817q.17346.1463.35609.28121c2.09937-3.95082,7.125-5.24231,11.59215-5.58556,21.38872-1.692,42.28155,8.25852,63.73432,7.50784-1.51355-5.23-3.69057-10.25571-4.92486-15.54841-5.4589-23.50169,8.15632-49.08916-.19073-71.72579-1.6675-4.52979-4.45348-8.98325-8.84294-10.96818a23.55527,23.55527,0,0,0-5.66189-1.49858c-5.42075-.97952-16.21183-5.166-21.45275-3.48622-1.93452.624-2.69742,2.44268-4.3009,3.54209C462.87722,455.90186,459.64576,456.474,457.62676,458.523Z"
19+
transform="translate(-160.68481 -208.5)" fill="#AEAFB0" />
20+
<path id="a38c3c09-000b-42b7-8619-0229d8aff5e9-5149" data-name="Path 1421"
21+
d="M754.67242,536.1831c-6.45068-2.76152-18.65315-1.06948-25.71553-1.27245-9.70666-.22892-19.96235.8024-27.928,6.3621-9.68351,6.7722-14.137,19.2008-14.0607,31.02182s4.04615,23.21839,8.29664,34.2533c2.36638,6.22174,4.86084,12.39318,5.68777,18.946,0,0-84.62988,10.0337-89.73865,14.14932s-7.39205,12.34819-3.474,17.43793,126.17305,10.19983,142.2691,6.794a5.08966,5.08966,0,0,0,5.21639-4.94937c1.62663-9.49139,2.93721-18.99642,3.81455-28.57778.46456-4.93706.80242-9.87421,1.14573-14.82359l3.65653-52.51275a45.04293,45.04293,0,0,0-.15258-11.10851C762.73613,546.90479,759.77712,538.431,754.67242,536.1831Z"
22+
transform="translate(-160.68481 -208.5)" fill="#DFE0E2" />
23+
<path id="bd3879bf-5d05-49be-b690-c4d97e29a2ab-5150" data-name="Path 1430"
24+
d="M734.68691,454.346c-1.60348-1.09941-2.36638-2.91813-4.3009-3.54209-5.24092-1.67976-16.032,2.5067-21.45275,3.48622a23.55527,23.55527,0,0,0-5.66189,1.49858c-4.38946,1.98493-7.17544,6.43839-8.84294,10.96818-8.34705,22.63663,5.26817,48.2241-.19073,71.72579-1.23429,5.2927-3.41131,10.3184-4.92486,15.54841,21.45277.75068,42.3456-9.19987,63.73432-7.50784,4.46712.34325,9.49278,1.63474,11.59215,5.58556q.18253-.13482.35609-.28121a7.02422,7.02422,0,0,0,.84005-9.89817,15.53466,15.53466,0,0,1-1.87049-2.023,7.32926,7.32926,0,0,1-.82693-3.55028,213.58786,213.58786,0,0,0-17.94066-73.31562,13.16962,13.16962,0,0,0-2.82413-4.51753C740.35424,456.474,737.12278,455.90186,734.68691,454.346Z"
25+
transform="translate(-160.68481 -208.5)" fill="#AEAFB0" />
26+
<path
27+
d="M741.57233,690.28819H479.54154a11.55237,11.55237,0,0,1-11.53931-11.53864V519.78292a11.55237,11.55237,0,0,1,11.53931-11.53864H741.57233a11.55237,11.55237,0,0,1,11.5393,11.53864V678.74955A11.55237,11.55237,0,0,1,741.57233,690.28819Z"
28+
transform="translate(-160.68481 -208.5)" fill="#999A9C" />
29+
<path
30+
d="M537.55552,334.04923h0c-11.3546,0-20.55934-9.95244-20.55934-22.22945h0V300.705c0-12.277,9.20473-22.22945,20.55933-22.22945h0v55.57369Z"
31+
transform="translate(-160.68481 -208.5)" fill="#AEAFB0" />
32+
<path
33+
d="M668.77923,278.47558h0c11.35461,0,20.55935,9.95245,20.55935,22.22943v11.11477c0,12.277-9.20472,22.22945-20.55935,22.22945h0V278.47558Z"
34+
transform="translate(-160.68481 -208.5)" fill="#AEAFB0" />
35+
<path
36+
d="M679.55259,302.45164h-3.262c0-44.73-33.65638-81.12069-75.026-81.12069-41.36939,0-75.02605,36.3907-75.02605,81.12069h-3.262c0-46.6749,35.11988-84.64766,78.288-84.64766C644.433,217.804,679.55259,255.77677,679.55259,302.45164Z"
37+
transform="translate(-160.68481 -208.5)" fill="#AEAFB0" />
38+
</g>
39+
</svg>
40+
} @else {
41+
<img [src]="url" #avatar alt="avatar" />
42+
}
43+
</div>
Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,43 @@
1-
:host {
2-
aspect-ratio: 1;
1+
.avatar {
32
position: relative;
43
line-height: 1;
5-
margin-right: 1rem;
6-
margin-bottom: 1rem;
4+
display: inline-flex;
5+
width: 100%;
6+
height: 100%;
7+
8+
&__circle {
9+
img, svg, &::before {
10+
border-radius: 100rem;
11+
}
12+
}
713

8-
&::before {
9-
content: '';
10-
background: repeating-linear-gradient(
11-
55deg,
12-
var(--blog-palette-accent),
13-
var(--blog-palette-accent) 5px,
14-
transparent 5px,
15-
transparent 10px
16-
);
17-
position: absolute;
18-
height: 100%;
19-
width: 100%;
20-
top: 0;
21-
left: 0;
22-
transform: translate(1rem, 1rem);
14+
&__shadow {
15+
&::before {
16+
content: '';
17+
background: repeating-linear-gradient(
18+
55deg,
19+
var(--blog-palette-accent),
20+
var(--blog-palette-accent) 5px,
21+
transparent 5px,
22+
transparent 10px
23+
);
24+
position: absolute;
25+
height: 100%;
26+
width: 100%;
27+
top: 0;
28+
left: 0;
29+
transform: translate(8%, 8%);
30+
}
2331
}
2432

25-
img {
33+
img, svg {
2634
position: relative;
35+
background: var(--blog-palette-neutral);
36+
width: 100%;
37+
height: 100%;
38+
}
39+
40+
svg > * {
41+
opacity: .5;
2742
}
2843
}
Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
1-
import { Component, Input } from '@angular/core';
2-
import { CommonModule } from '@angular/common';
1+
import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core';
2+
import { NgClass } from '@angular/common';
33

44
@Component({
55
selector: 'blog-avatar',
66
standalone: true,
7-
imports: [CommonModule],
7+
imports: [NgClass],
88
templateUrl: './avatar.component.html',
99
styleUrl: './avatar.component.scss',
1010
})
11-
export class AvatarComponent {
12-
@Input() url: string | null = null;
11+
export class AvatarComponent implements AfterViewInit {
12+
13+
@Input() url!: string | undefined;
14+
@Input() format: 'circle' | 'square' = 'circle';
15+
@Input() shadow = false;
16+
17+
@ViewChild('avatar')
18+
image!: ElementRef;
19+
20+
placeholder: boolean = false;
21+
22+
ngAfterViewInit(): void {
23+
this.image?.nativeElement?.addEventListener('error', () => {
24+
this.placeholder = true
25+
});
26+
}
27+
1328
}

0 commit comments

Comments
 (0)