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

Commit 51fe82e

Browse files
merge: reorder slides
2 parents 14fdada + 4e69b05 commit 51fe82e

File tree

12 files changed

+161
-20
lines changed

12 files changed

+161
-20
lines changed

studio/package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

studio/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"test.watch": "stencil test --spec --e2e --watch"
1515
},
1616
"dependencies": {
17-
"@deckdeckgo/core": "^1.0.0-beta.41",
17+
"@deckdeckgo/core": "^1.0.0-beta.42",
1818
"@deckdeckgo/highlight-code": "^1.0.0-alpha.16",
1919
"@deckdeckgo/inline-editor": "^1.0.0-alpha.10",
2020
"@deckdeckgo/lazy-img": "^1.0.0-alpha.10",

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ export class AppEditorActions {
217217

218218
<ion-tab-button onClick={() => this.openSlideNavigate()} color="primary" class="wider-devices"
219219
mode="md">
220-
<ion-icon src="/assets/icons/chapters.svg"></ion-icon>
221-
<ion-label>Go to slide</ion-label>
220+
<ion-icon src="/assets/icons/ionicons/list.svg"></ion-icon>
221+
<ion-label>Slides</ion-label>
222222
</ion-tab-button>
223223

224224
<ion-tab-button onClick={() => this.toggleFullScreenMode()} color="primary" class="wider-devices" mode="md">

studio/src/app/handlers/editor/events/deck/deck-events.handler.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {ItemReorderEventDetail} from '@ionic/core';
2+
13
import {Subject, Subscription} from 'rxjs';
24
import {debounceTime, filter, take} from 'rxjs/operators';
35

@@ -615,4 +617,33 @@ export class DeckEventsHandler {
615617
resolve();
616618
});
617619
}
620+
621+
updateDeckSlidesOrder(detail: ItemReorderEventDetail): Promise<void> {
622+
return new Promise<void>(async (resolve, reject) => {
623+
try {
624+
if (!detail) {
625+
reject('No new order provided for the slides');
626+
return;
627+
}
628+
629+
if (detail.from < 0 || detail.to < 0 || detail.from === detail.to) {
630+
reject('The new order provided for the slides is not valid');
631+
return;
632+
}
633+
634+
this.deckEditorService.watch().pipe(take(1)).subscribe(async (deck: Deck) => {
635+
if (deck && deck.data && deck.data.slides && detail.to < deck.data.slides.length) {
636+
deck.data.slides.splice(detail.to, 0, ...deck.data.slides.splice(detail.from, 1));
637+
638+
const updatedDeck: Deck = await this.deckService.update(deck);
639+
this.deckEditorService.next(updatedDeck);
640+
}
641+
642+
resolve();
643+
});
644+
} catch (err) {
645+
reject(err);
646+
}
647+
});
648+
}
618649
}

studio/src/app/handlers/editor/events/remote/remote-events.handler.tsx

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ export class RemoteEventsHandler {
239239

240240
deckgoRemoteElement.slides = $event.detail;
241241

242-
await this.updateRemoteSlides($event);
242+
await this.updateRemoteSlidesOnSlidesDidLoad($event);
243243

244244
resolve();
245245
});
@@ -392,7 +392,7 @@ export class RemoteEventsHandler {
392392
});
393393
}
394394

395-
private updateRemoteSlides($event: CustomEvent): Promise<void> {
395+
private updateRemoteSlidesOnSlidesDidLoad($event: CustomEvent): Promise<void> {
396396
return new Promise<void>(async (resolve) => {
397397
const deck: HTMLElement = this.el.querySelector('deckgo-deck');
398398

@@ -409,6 +409,46 @@ export class RemoteEventsHandler {
409409
return;
410410
}
411411

412+
await this.updateRemoteSlides();
413+
414+
resolve();
415+
});
416+
}
417+
418+
updateRemoteSlidesOnMutation(): Promise<void> {
419+
return new Promise<void>(async (resolve) => {
420+
const deck: HTMLElement = this.el.querySelector('deckgo-deck');
421+
422+
if (!deck || !deck.hasChildNodes()) {
423+
resolve();
424+
return;
425+
}
426+
427+
const observer: MutationObserver = new MutationObserver(async (_mutations: MutationRecord[], _observer: MutationObserver) => {
428+
429+
const slidesDefinition: any[] = await (deck as any).getSlidesDefinition();
430+
431+
if (slidesDefinition && slidesDefinition.length > 0) {
432+
const deckgoRemoteElement = this.el.querySelector('deckgo-remote');
433+
434+
if (deckgoRemoteElement) {
435+
deckgoRemoteElement.slides = slidesDefinition;
436+
437+
await this.updateRemoteSlides();
438+
}
439+
}
440+
441+
observer.disconnect();
442+
});
443+
444+
observer.observe(deck, {childList: true, subtree: true});
445+
446+
resolve();
447+
});
448+
}
449+
450+
private updateRemoteSlides(): Promise<void> {
451+
return new Promise<void>(async (resolve) => {
412452
const deckgoRemoteElement = this.el.querySelector('deckgo-remote');
413453

414454
if (!deckgoRemoteElement) {
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
app-slide-navigate {
2-
ion-list {
2+
ion-reorder-group {
33
ion-item {
44
--border-color: transparent;
55
}
66
}
7+
8+
p {
9+
font-size: var(--font-size-very-small);
10+
}
711
}

studio/src/app/modals/editor/app-slide-navigate/app-slide-navigate.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {Component, Listen, Element, State, h} from '@stencil/core';
1+
import {Component, Listen, Element, State, h, EventEmitter, Event} from '@stencil/core';
2+
import {ItemReorderEventDetail} from '@ionic/core';
23

34
@Component({
45
tag: 'app-slide-navigate',
@@ -11,6 +12,8 @@ export class AppSlideNavigate {
1112
@State()
1213
slides: string[];
1314

15+
@Event() private reorder: EventEmitter<ItemReorderEventDetail>;
16+
1417
async componentDidLoad() {
1518
history.pushState({modal: true}, null);
1619

@@ -26,7 +29,7 @@ export class AppSlideNavigate {
2629
await (this.el.closest('ion-modal') as HTMLIonModalElement).dismiss();
2730
}
2831

29-
private async jumpToSlide(index: number) {
32+
async jumpToSlide(index: number) {
3033
await (this.el.closest('ion-modal') as HTMLIonModalElement).dismiss(index);
3134
}
3235

@@ -71,6 +74,19 @@ export class AppSlideNavigate {
7174
});
7275
}
7376

77+
private onReorder($event: CustomEvent<ItemReorderEventDetail>): Promise<void> {
78+
return new Promise<void>((resolve) => {
79+
if (!$event) {
80+
resolve();
81+
return;
82+
}
83+
84+
this.reorder.emit($event.detail);
85+
86+
resolve();
87+
});
88+
}
89+
7490
render() {
7591
return [
7692
<ion-header>
@@ -80,13 +96,15 @@ export class AppSlideNavigate {
8096
<ion-icon name="close"></ion-icon>
8197
</ion-button>
8298
</ion-buttons>
83-
<ion-title class="ion-text-uppercase">Go to slide</ion-title>
99+
<ion-title class="ion-text-uppercase">Slides</ion-title>
84100
</ion-toolbar>
85101
</ion-header>,
86102
<ion-content class="ion-padding">
87-
<ion-list>
103+
<p class="ion-padding-start ion-padding-end">Jump to a specific slide or change the order of your slides.</p>
104+
105+
<ion-reorder-group onIonItemReorder={($event: CustomEvent<ItemReorderEventDetail>) => this.onReorder($event)} disabled={!this.slides || this.slides.length <= 1}>
88106
{this.renderSlides()}
89-
</ion-list>
107+
</ion-reorder-group>
90108
</ion-content>
91109
];
92110
}
@@ -98,8 +116,9 @@ export class AppSlideNavigate {
98116

99117
const text = 'Slide ' + (i + 1) + (slideTitle ? ': ' + slideTitle : '');
100118

101-
return <ion-item ion-item button onClick={() => this.jumpToSlide(i)}>
119+
return <ion-item ion-item button onClick={() => this.jumpToSlide(i)} detail={false}>
102120
<ion-label>{text}</ion-label>
121+
<ion-reorder slot="end"></ion-reorder>
103122
</ion-item>
104123
})
105124
);

studio/src/app/pages/editor/app-editor/app-editor.tsx

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

3+
import {ItemReorderEventDetail} from '@ionic/core';
4+
35
import {Subscription} from 'rxjs';
46
import {filter, take} from 'rxjs/operators';
57

@@ -87,7 +89,7 @@ export class AppEditor {
8789
this.busyService = BusyService.getInstance();
8890
}
8991

90-
@Listen('ionRouteDidChange', { target: 'window' })
92+
@Listen('ionRouteDidChange', {target: 'window'})
9193
async onRouteDidChange($event: CustomEvent) {
9294
if (!$event || !$event.detail) {
9395
return;
@@ -479,6 +481,45 @@ export class AppEditor {
479481
this.hideNavigation = $event ? DeckDeckGoUtils.isIOS() && $event.detail : false;
480482
}
481483

484+
@Listen('reorder', {target: 'document'})
485+
async onReorderSlides($event: CustomEvent<ItemReorderEventDetail>) {
486+
if (!$event || !$event.detail) {
487+
return;
488+
}
489+
490+
await this.reorderSlides($event.detail);
491+
}
492+
493+
private reorderSlides(detail: ItemReorderEventDetail): Promise<void> {
494+
return new Promise<void>(async (resolve) => {
495+
if (!detail) {
496+
resolve();
497+
return;
498+
}
499+
500+
try {
501+
await this.deckEventsHandler.updateDeckSlidesOrder(detail);
502+
503+
if (detail.from < 0 || detail.to < 0 || !this.slides || detail.to >= this.slides.length || detail.from === detail.to) {
504+
resolve();
505+
return;
506+
}
507+
508+
await this.remoteEventsHandler.updateRemoteSlidesOnMutation();
509+
510+
this.slides.splice(detail.to, 0, ...this.slides.splice(detail.from, 1));
511+
this.slides = [...this.slides];
512+
} catch (err) {
513+
// We ignore the error here
514+
}
515+
516+
// Finish the reorder and position the item in the DOM based on where the gesture ended. This method can also be called directly by the reorder group
517+
detail.complete();
518+
519+
resolve();
520+
});
521+
}
522+
482523
render() {
483524
return [
484525
<app-navigation publish={true} class={this.hideNavigation ? 'hidden' : undefined}></app-navigation>,
@@ -502,7 +543,8 @@ export class AppEditor {
502543
<app-editor-toolbar></app-editor-toolbar>
503544
</ion-content>,
504545
<ion-footer class={this.presenting ? 'idle' : undefined}>
505-
<app-editor-actions hideFooterActions={this.hideFooterActions} fullscreen={this.fullscreen} slides={this.slides}
546+
<app-editor-actions hideFooterActions={this.hideFooterActions} fullscreen={this.fullscreen}
547+
slides={this.slides}
506548
onSignIn={() => this.signIn()}
507549
onAddSlide={($event: CustomEvent<any>) => this.addSlide($event)}
508550
onAnimatePrevNextSlide={($event: CustomEvent<boolean>) => this.animatePrevNextSlide($event)}

studio/src/app/popovers/editor/actions/app-more-actions/app-more-actions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class AppMoreActions {
3131

3232
render() {
3333
return <div class="ion-padding">
34-
<a onClick={() => this.closePopover(MoreAction.JUMP_TO)}><p>Go to slide</p></a>
34+
<a onClick={() => this.closePopover(MoreAction.JUMP_TO)}><p>Slides</p></a>
3535
{this.renderFullscreenOption()}
3636
<a onClick={() => this.closePopover(MoreAction.REMOTE)}><p>Remote control</p></a>
3737
<app-share-options onSelectedOption={($event: CustomEvent<MoreAction>) => this.closeSharePopover($event)}></app-share-options>

studio/src/assets/icons/chapters.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)