Skip to content
This repository was archived by the owner on Feb 6, 2024. It is now read-only.

Commit 774424f

Browse files
feat: keep track of the last 10 images/stock photos used in order to user them again easily
1 parent a5a70fc commit 774424f

File tree

11 files changed

+324
-96
lines changed

11 files changed

+324
-96
lines changed

studio/src/app/components/editor/app-editor-toolbar/app-editor-toolbar.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,8 @@ export class AppEditorToolbar {
659659
await this.openPhotos();
660660
} else if (detail.data.action === ImageAction.DELETE_PHOTO) {
661661
await this.deleteBackgroundPhoto();
662+
} else if (detail.data.action === ImageAction.ADD_PHOTO && detail.data.photo) {
663+
await this.appendPhoto(detail.data.photo as UnsplashPhoto);
662664
}
663665
}
664666
});
@@ -673,14 +675,32 @@ export class AppEditorToolbar {
673675

674676
modal.onDidDismiss().then(async (detail: OverlayEventDetail) => {
675677
if (detail && detail.data && this.selectedElement) {
676-
const helper: PhotoHelper = new PhotoHelper(this.slideDidChange, this.deckDidChange);
677-
await helper.appendPhoto(this.selectedElement, (detail.data as UnsplashPhoto), this.deckOrSlide, this.applyToAllDeck);
678+
await this.appendPhoto(detail.data as UnsplashPhoto);
678679
}
679680
});
680681

681682
await modal.present();
682683
}
683684

685+
private appendPhoto(photo: UnsplashPhoto): Promise<void> {
686+
return new Promise<void>(async (resolve) => {
687+
if (!this.selectedElement) {
688+
resolve();
689+
return;
690+
}
691+
692+
if (!photo) {
693+
resolve();
694+
return;
695+
}
696+
697+
const helper: PhotoHelper = new PhotoHelper(this.slideDidChange, this.deckDidChange);
698+
await helper.appendPhoto(this.selectedElement, photo, this.deckOrSlide, this.applyToAllDeck);
699+
700+
resolve();
701+
});
702+
}
703+
684704
private deleteBackgroundPhoto(): Promise<void> {
685705
return new Promise<void>(async (resolve) => {
686706
if (!this.deckOrSlide) {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
div.photos-container {
2+
display: flex;
3+
flex-direction: row;
4+
flex-wrap: wrap;
5+
6+
div.photos-column {
7+
display: block;
8+
flex-grow: 1;
9+
flex-basis: 50%;
10+
max-width: 50%;
11+
12+
div.photo {
13+
position: relative;
14+
padding: var(--deckgo-stock-photos-padding);
15+
16+
touch-action: manipulation;
17+
cursor: pointer;
18+
19+
div.photo-container {
20+
border-radius: 4px;
21+
overflow: hidden;
22+
position: relative;
23+
24+
img {
25+
width: 100%;
26+
height: auto;
27+
min-height: var(--deckgo-stock-photos-min-height);
28+
vertical-align: top;
29+
}
30+
31+
ion-label.photo-credits {
32+
position: absolute;
33+
bottom: 0;
34+
right: 0;
35+
background: rgba(var(--ion-color-dark-rgb), 0.4);
36+
padding: 4px 8px;
37+
font-size: var(--font-size-very-small);
38+
color: white;
39+
40+
a {
41+
color: white;
42+
text-decoration: inherit;
43+
44+
&:hover, &:active {
45+
color: white;
46+
}
47+
}
48+
}
49+
}
50+
}
51+
}
52+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import {Component, Event, EventEmitter, Prop} from '@stencil/core';
2+
3+
@Component({
4+
tag: 'app-stock-photos',
5+
styleUrl: 'app-stock-photos.scss',
6+
shadow: true
7+
})
8+
export class AppStockPhotos {
9+
10+
@Prop()
11+
photosOdd: UnsplashPhoto[];
12+
13+
@Prop()
14+
photosEven: UnsplashPhoto[];
15+
16+
@Event() private selectPhoto: EventEmitter<UnsplashPhoto>;
17+
18+
render() {
19+
return <div class="photos-container">
20+
<div class="photos-column">
21+
{this.renderPhotos(this.photosOdd)}
22+
</div>
23+
<div class="photos-column">
24+
{this.renderPhotos(this.photosEven)}
25+
</div>
26+
</div>
27+
}
28+
29+
private renderPhotos(photos: UnsplashPhoto[]) {
30+
if (photos && photos.length > 0) {
31+
return (
32+
photos.map((photo: UnsplashPhoto) => {
33+
if (photo.urls && photo.urls.thumb) {
34+
return <div class="photo ion-padding" custom-tappable onClick={() => this.selectPhoto.emit(photo)}>
35+
<div class="photo-container">
36+
<img src={photo.urls.thumb}
37+
alt={photo.description ? photo.description : (photo.links && photo.links.html ? photo.links.html : photo.urls.thumb)}></img>
38+
{this.renderPhotoCredits(photo)}
39+
</div>
40+
</div>
41+
} else {
42+
return undefined;
43+
}
44+
})
45+
);
46+
} else {
47+
return undefined;
48+
}
49+
}
50+
51+
private renderPhotoCredits(photo: UnsplashPhoto) {
52+
if (!photo.user || !photo.user.links || !photo.user.links.html || !photo.user.name) {
53+
return undefined;
54+
} else {
55+
return <ion-label class="photo-credits"><a
56+
href={photo.user.links.html + '?utm_source=DeckDeckGo&utm_medium=referral'} target="_blank"
57+
onClick={($event: UIEvent) => $event.stopPropagation()}>{photo.user.name}</a></ion-label>;
58+
}
59+
}
60+
61+
}

studio/src/app/modals/editor/app-photo/app-photo.scss

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,9 @@ app-photo {
33
--background: var(--ion-color-light);
44
}
55

6-
div.photos-container {
7-
display: flex;
8-
flex-direction: row;
9-
flex-wrap: wrap;
10-
11-
div.photos-column {
12-
display: block;
13-
flex-grow: 1;
14-
flex-basis: 50%;
15-
max-width: 50%;
16-
17-
div.photo {
18-
position: relative;
19-
20-
div.photo-container {
21-
border-radius: 4px;
22-
overflow: hidden;
23-
position: relative;
24-
25-
img {
26-
width: 100%;
27-
height: auto;
28-
min-height: 5rem;
29-
vertical-align: top;
30-
}
31-
32-
ion-label.photo-credits {
33-
position: absolute;
34-
bottom: 0;
35-
right: 0;
36-
background: rgba(var(--ion-color-dark-rgb), 0.4);
37-
padding: 4px 8px;
38-
font-size: var(--font-size-very-small);
39-
color: white;
40-
41-
a {
42-
color: white;
43-
text-decoration: inherit;
44-
45-
&:hover, &:active {
46-
color: white;
47-
}
48-
}
49-
}
50-
}
51-
}
52-
}
6+
app-stock-photos {
7+
--deckgo-stock-photos-min-height: 5rem;
8+
--deckgo-stock-photos-padding: 16px;
539
}
5410

5511
div.photos-placeholder {

studio/src/app/modals/editor/app-photo/app-photo.tsx

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {Component, Element, Listen, State} from '@stencil/core';
22

33
import {PhotoService} from '../../../services/api/photo/photo.service';
4+
import {PhotoHistoryService} from '../../../services/editor/photo-history/photo-history.service';
45

56
@Component({
67
tag: 'app-photo',
@@ -11,6 +12,7 @@ export class AppPhoto {
1112
@Element() el: HTMLElement;
1213

1314
private photoService: PhotoService;
15+
private photoHistoryService: PhotoHistoryService;
1416

1517
@State()
1618
private photosOdd: UnsplashPhoto[];
@@ -30,6 +32,7 @@ export class AppPhoto {
3032

3133
constructor() {
3234
this.photoService = PhotoService.getInstance();
35+
this.photoHistoryService = PhotoHistoryService.getInstance();
3336
}
3437

3538
async componentDidLoad() {
@@ -45,10 +48,19 @@ export class AppPhoto {
4548
await (this.el.closest('ion-modal') as HTMLIonModalElement).dismiss();
4649
}
4750

48-
private selectPhoto(photo: UnsplashPhoto): Promise<void> {
51+
private selectPhoto($event: CustomEvent): Promise<void> {
4952
return new Promise<void>(async (resolve) => {
53+
if (!$event || !$event.detail) {
54+
resolve();
55+
return;
56+
}
57+
58+
const photo: UnsplashPhoto = $event.detail;
59+
5060
await this.photoService.registerDownload(photo.id);
5161

62+
await this.photoHistoryService.push(photo);
63+
5264
await (this.el.closest('ion-modal') as HTMLIonModalElement).dismiss(photo);
5365

5466
resolve();
@@ -111,8 +123,8 @@ export class AppPhoto {
111123
this.photosEven = [];
112124
}
113125

114-
this.photosOdd = [...this.photosOdd, ...photos.filter((_a, i) => i % 2)];
115-
this.photosEven = [...this.photosEven, ...photos.filter((_a, i) => !(i % 2))];
126+
this.photosEven = [...this.photosEven, ...photos.filter((_a, i) => i % 2)];
127+
this.photosOdd = [...this.photosOdd, ...photos.filter((_a, i) => !(i % 2))];
116128

117129
if (!this.paginationNext || this.paginationNext === 0 || newSearchTerm) {
118130
// We just put a small delay because of the repaint
@@ -176,14 +188,9 @@ export class AppPhoto {
176188
</ion-toolbar>
177189
</ion-header>,
178190
<ion-content class="ion-padding">
179-
<div class="photos-container">
180-
<div class="photos-column">
181-
{this.renderPhotos(this.photosOdd)}
182-
</div>
183-
<div class="photos-column">
184-
{this.renderPhotos(this.photosEven)}
185-
</div>
186-
</div>
191+
<app-stock-photos photosOdd={this.photosOdd} photosEven={this.photosEven}
192+
onSelectPhoto={($event: CustomEvent) => this.selectPhoto($event)}>
193+
</app-stock-photos>
187194

188195
{this.renderPhotosPlaceHolder()}
189196

@@ -200,41 +207,14 @@ export class AppPhoto {
200207
<ion-searchbar debounce={500} placeholder="Search" value={this.searchTerm}
201208
onIonClear={() => this.clear()}
202209
onIonInput={(e: CustomEvent<KeyboardEvent>) => this.handleInput(e)}
203-
onIonChange={() => {this.search()}}></ion-searchbar>
210+
onIonChange={() => {
211+
this.search()
212+
}}></ion-searchbar>
204213
</ion-toolbar>
205214
</ion-footer>
206215
];
207216
}
208217

209-
private renderPhotos(photos: UnsplashPhoto[]) {
210-
if (photos && photos.length > 0) {
211-
return (
212-
photos.map((photo: UnsplashPhoto) => {
213-
if (photo.urls && photo.urls.thumb) {
214-
return <div class="photo ion-padding" custom-tappable onClick={() => this.selectPhoto(photo)}>
215-
<div class="photo-container">
216-
<img src={photo.urls.thumb} alt={photo.description ? photo.description : (photo.links && photo.links.html ? photo.links.html : photo.urls.thumb)}></img>
217-
{this.renderPhotoCredits(photo)}
218-
</div>
219-
</div>
220-
} else {
221-
return undefined;
222-
}
223-
})
224-
);
225-
} else {
226-
return undefined;
227-
}
228-
}
229-
230-
private renderPhotoCredits(photo: UnsplashPhoto) {
231-
if (!photo.user || !photo.user.links || !photo.user.links.html || !photo.user.name) {
232-
return undefined;
233-
} else {
234-
return <ion-label class="photo-credits"><a href={photo.user.links.html + '?utm_source=DeckDeckGo&utm_medium=referral'} target="_blank" onClick={($event: UIEvent) => $event.stopPropagation()}>{photo.user.name}</a></ion-label>;
235-
}
236-
}
237-
238218
private renderPhotosPlaceHolder() {
239219
if ((!this.photosOdd || this.photosOdd.length <= 0) && (!this.photosEven || this.photosEven.length <= 0)) {
240220
return <div class="photos-placeholder">

studio/src/app/popovers/core/app-user-menu/app-user-menu.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {Component, Element} from '@stencil/core';
22

33
import {AuthService} from '../../../services/api/auth/auth.service';
44
import {NavDirection, NavService} from '../../../services/core/nav/nav.service';
5+
import {PhotoHistoryService} from '../../../services/editor/photo-history/photo-history.service';
56

67
@Component({
78
tag: 'app-user-menu',
@@ -14,13 +15,19 @@ export class AppUserMenu {
1415
private authService: AuthService;
1516
private navService: NavService;
1617

18+
private photoHistoryService: PhotoHistoryService;
19+
1720
constructor() {
1821
this.authService = AuthService.getInstance();
1922
this.navService = NavService.getInstance();
23+
this.photoHistoryService = PhotoHistoryService.getInstance();
24+
2025
}
2126

2227
private async signOut() {
2328
await this.authService.signOut();
29+
await this.photoHistoryService.clear();
30+
2431
await this.closePopover();
2532

2633
this.navService.navigate({

studio/src/app/popovers/editor/app-image/app-image.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@ app-image {
2828
margin: 16px 0 4px;
2929
}
3030
}
31+
32+
app-stock-photos {
33+
--deckgo-stock-photos-padding: 4px;
34+
}
3135
}

0 commit comments

Comments
 (0)