From 1a95e1276e1d947a3ca9abad3255c9cc4731c614 Mon Sep 17 00:00:00 2001 From: peterpeterparker Date: Wed, 18 Aug 2021 14:36:04 +0200 Subject: [PATCH 1/4] fix: selector for main deck --- .../events/remote/remote-events.handler.ts | 26 ++++++++++--------- .../pages/editor/app-editor/app-editor.tsx | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/studio/src/app/handlers/editor/events/remote/remote-events.handler.ts b/studio/src/app/handlers/editor/events/remote/remote-events.handler.ts index 99f4617bd..b8491f0a8 100644 --- a/studio/src/app/handlers/editor/events/remote/remote-events.handler.ts +++ b/studio/src/app/handlers/editor/events/remote/remote-events.handler.ts @@ -9,6 +9,8 @@ import {ConnectionState, DeckdeckgoDeckDefinition, DeckdeckgoEventDeckRequest, D import {EnvironmentDeckDeckGoConfig} from '../../../../types/core/environment-config'; import {EnvironmentConfigService} from '../../../../services/environment/environment-config.service'; +import {deckSelector} from '../../../../utils/editor/deck.utils'; + import {RemoteService} from '../../../../services/editor/remote/remote.service'; export class RemoteEventsHandler { @@ -74,7 +76,7 @@ export class RemoteEventsHandler { }); } - const deck: HTMLElement = this.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (deck) { deck.removeEventListener('slidesDidLoad', async ($event: CustomEvent) => { @@ -171,7 +173,7 @@ export class RemoteEventsHandler { return; } - const deck = this.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deck) { resolve(); @@ -208,7 +210,7 @@ export class RemoteEventsHandler { return new Promise(async (resolve) => { const deckgoRemoteElement = this.el.querySelector('deckgo-remote'); - const deck = this.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deckgoRemoteElement || !deck) { resolve(); @@ -233,7 +235,7 @@ export class RemoteEventsHandler { private youtubePlayPause($event) { return new Promise(async (resolve) => { - const deck = this.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deck) { resolve(); @@ -261,7 +263,7 @@ export class RemoteEventsHandler { private initSlidesDidLoadListener() { return new Promise(async (resolve) => { - const deck: HTMLElement = this.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deck) { resolve(); @@ -294,7 +296,7 @@ export class RemoteEventsHandler { private initDeckMove() { return new Promise(async (resolve) => { - const deck: HTMLElement = this.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deck) { resolve(); @@ -421,7 +423,7 @@ export class RemoteEventsHandler { await deckgoRemoteElement.connect(); - const deckElement: HTMLDeckgoDeckElement | null = this.el.querySelector('deckgo-deck'); + const deckElement: HTMLDeckgoDeckElement | null = document.querySelector(deckSelector); if (!deckElement) { return; @@ -452,7 +454,7 @@ export class RemoteEventsHandler { private updateRemoteSlidesOnSlidesDidLoad($event: CustomEvent): Promise { return new Promise(async (resolve) => { - const deck: HTMLElement = this.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deck || !$event || !$event.detail || !deck.hasChildNodes()) { resolve(); @@ -475,7 +477,7 @@ export class RemoteEventsHandler { updateRemoteSlidesOnMutation(): Promise { return new Promise(async (resolve) => { - const deck: HTMLElement = this.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deck || !deck.hasChildNodes()) { resolve(); @@ -496,7 +498,7 @@ export class RemoteEventsHandler { private updateRemoteDeckWithDefinition(self): Promise { return new Promise(async (resolve) => { - const deck: HTMLElement = self.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deck || !deck.hasChildNodes()) { resolve(); @@ -521,7 +523,7 @@ export class RemoteEventsHandler { private updateCurrentSlideWithDefinition(self): Promise { return new Promise(async (resolve) => { - const deck: HTMLElement = self.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deck || !deck.hasChildNodes()) { resolve(); @@ -545,7 +547,7 @@ export class RemoteEventsHandler { return; } - const deck: HTMLElement = self.el.querySelector('deckgo-deck'); + const deck: HTMLDeckgoDeckElement = document.querySelector(deckSelector); if (!deck || !deck.hasChildNodes()) { resolve(); diff --git a/studio/src/app/pages/editor/app-editor/app-editor.tsx b/studio/src/app/pages/editor/app-editor/app-editor.tsx index ed8dec39d..dd3845c47 100644 --- a/studio/src/app/pages/editor/app-editor/app-editor.tsx +++ b/studio/src/app/pages/editor/app-editor/app-editor.tsx @@ -334,7 +334,7 @@ export class AppEditor { private async concatSlide(extraSlide: JSX.IntrinsicElements) { this.slides = [...this.slides, extraSlide]; - await ParseDeckSlotsUtils.stickLastChildren(this.el); + await ParseDeckSlotsUtils.stickLastChildren(this.mainRef); } private async replaceSlide(slide: JSX.IntrinsicElements) { From 817234dafefb69aa93d2c5f53c68b36a77fa4391 Mon Sep 17 00:00:00 2001 From: peterpeterparker Date: Wed, 18 Aug 2021 17:12:30 +0200 Subject: [PATCH 2/4] feat: drag and drop slides --- .../app-slides-aside/app-slides-aside.scss | 16 +++++ .../app-slides-aside/app-slides-aside.tsx | 67 ++++++++++++++++++- .../pages/editor/app-editor/app-editor.tsx | 42 ++++++------ .../app-slide-navigate/app-slide-navigate.tsx | 3 +- studio/src/components.d.ts | 1 + 5 files changed, 102 insertions(+), 27 deletions(-) diff --git a/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.scss b/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.scss index bbcc0a207..49b90a207 100644 --- a/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.scss +++ b/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.scss @@ -15,5 +15,21 @@ app-slides-aside { app-slide-thumbnail { margin-bottom: 16px; + + transition: margin 0.25s ease-out, min-height 0.25s ease-in; + + &.hover { + margin-bottom: calc((var(--slides-aside-width) - 32px) * 9 / 16); + } + + &.drag-start, &.drag-hover { + visibility: hidden; + opacity: 0; + } + + &.drag-hover { + min-height: 0; + border: none; + } } } diff --git a/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.tsx b/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.tsx index e5907ad5b..8d0e2b517 100644 --- a/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.tsx +++ b/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.tsx @@ -1,4 +1,6 @@ -import {Component, Listen, h, Host, State, Prop} from '@stencil/core'; +import {Component, Listen, h, Host, State, Prop, Event, EventEmitter} from '@stencil/core'; + +import {ItemReorderEventDetail} from '@ionic/core'; import {debounce} from '@deckdeckgo/utils'; @@ -16,6 +18,12 @@ export class AppSlidesAside { @Prop() deckRef!: HTMLDeckgoDeckElement; + @Event() + private reorder: EventEmitter; + + @State() + private reorderDetail: ItemReorderEventDetail | undefined = undefined; + private readonly debounceUpdateAllSlides: () => void; private readonly debounceUpdateSlide: (updateSlide: HTMLElement) => void; @@ -67,16 +75,69 @@ export class AppSlidesAside { .map((slide: HTMLElement) => slide.cloneNode(true) as HTMLElement); } + private onDragStart(from: number) { + this.reorderDetail = { + from, + to: undefined, + complete: () => {} + }; + + console.log(this.reorderDetail); + } + + private onDragHover(to: number) { + if (!this.reorderDetail) { + return; + } + + this.reorderDetail = { + ...this.reorderDetail, + to + }; + } + + private onDrop() { + if (!this.reorderDetail || this.reorderDetail.to === undefined) { + return; + } + + const {from, to, complete} = this.reorderDetail; + const detail = { + from, + to: from > to ? to + 1 : to, + complete + }; + + this.reorder.emit(detail); + + this.slides.splice(detail.to, 0, ...this.slides.splice(detail.from, 1)); + this.slides = [...this.slides]; + + this.reorderDetail = undefined; + } + render() { return ( - + this.onDrop()} onDragOver={($event: DragEvent) => $event.preventDefault()}> {this.slides.map((slide: HTMLElement, index: number) => ( await slideTo(index)} key={slide.getAttribute('slide_id')} slide={slide} - deck={this.deckRef}> + deck={this.deckRef} + class={ + index === this.reorderDetail?.to && this.reorderDetail?.from !== this.reorderDetail?.to + ? 'hover' + : index === this.reorderDetail?.from + ? index === this.reorderDetail?.to + ? 'drag-start' + : 'drag-hover' + : '' + } + draggable={true} + onDragStart={() => this.onDragStart(index)} + onDragOver={() => this.onDragHover(index)}> ))} ); diff --git a/studio/src/app/pages/editor/app-editor/app-editor.tsx b/studio/src/app/pages/editor/app-editor/app-editor.tsx index dd3845c47..63992a792 100644 --- a/studio/src/app/pages/editor/app-editor/app-editor.tsx +++ b/studio/src/app/pages/editor/app-editor/app-editor.tsx @@ -676,6 +676,8 @@ export class AppEditor { @Listen('reorder', {target: 'document'}) async onReorderSlides($event: CustomEvent) { + console.log($event); + if (!$event || !$event.detail) { return; } @@ -683,34 +685,28 @@ export class AppEditor { await this.reorderSlides($event.detail); } - private reorderSlides(detail: ItemReorderEventDetail): Promise { - return new Promise(async (resolve) => { - if (!detail) { - resolve(); - return; - } - - try { - await this.deckEventsHandler.updateDeckSlidesOrder(detail); + private async reorderSlides(detail: ItemReorderEventDetail) { + if (!detail) { + return; + } - if (detail.from < 0 || detail.to < 0 || !this.slides || detail.to >= this.slides.length || detail.from === detail.to) { - resolve(); - return; - } + if (detail.from < 0 || detail.to < 0 || !this.slides || detail.to >= this.slides.length || detail.from === detail.to) { + return; + } - await this.remoteEventsHandler.updateRemoteSlidesOnMutation(); + try { + await this.deckEventsHandler.updateDeckSlidesOrder(detail); - this.slides.splice(detail.to, 0, ...this.slides.splice(detail.from, 1)); - this.slides = [...this.slides]; - } catch (err) { - // We ignore the error here - } + await this.remoteEventsHandler.updateRemoteSlidesOnMutation(); - // 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 - detail.complete(); + this.slides.splice(detail.to, 0, ...this.slides.splice(detail.from, 1)); + this.slides = [...this.slides]; + } catch (err) { + // We ignore the error here + } - resolve(); - }); + // 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 + detail.complete(); } private async updatePresenting(presenting: boolean) { diff --git a/studio/src/app/popovers/editor/app-slide-navigate/app-slide-navigate.tsx b/studio/src/app/popovers/editor/app-slide-navigate/app-slide-navigate.tsx index 61f6538c3..164a90af2 100644 --- a/studio/src/app/popovers/editor/app-slide-navigate/app-slide-navigate.tsx +++ b/studio/src/app/popovers/editor/app-slide-navigate/app-slide-navigate.tsx @@ -18,7 +18,8 @@ export class AppSlideNavigate { @State() private slides: string[]; - @Event() private reorder: EventEmitter; + @Event() + private reorder: EventEmitter; async componentDidLoad() { history.pushState({modal: true}, null); diff --git a/studio/src/components.d.ts b/studio/src/components.d.ts index 4abb8762a..b23ebc093 100644 --- a/studio/src/components.d.ts +++ b/studio/src/components.d.ts @@ -1692,6 +1692,7 @@ declare namespace LocalJSX { } interface AppSlidesAside { "deckRef": HTMLDeckgoDeckElement; + "onReorder"?: (event: CustomEvent) => void; } interface AppSlotType { "onSelectType"?: (event: CustomEvent) => void; From 84b10aea494e00cb8eea51f3695a206d311aafdf Mon Sep 17 00:00:00 2001 From: peterpeterparker Date: Wed, 18 Aug 2021 17:27:49 +0200 Subject: [PATCH 3/4] feat: drag and drop slides on top slide --- .../app-slides-aside/app-slides-aside.scss | 12 ++++++++- .../app-slides-aside/app-slides-aside.tsx | 25 ++++++++++++++++--- .../pages/editor/app-editor/app-editor.tsx | 2 -- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.scss b/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.scss index 49b90a207..3eab63e92 100644 --- a/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.scss +++ b/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.scss @@ -13,15 +13,25 @@ app-slides-aside { --preview-width: calc(var(--slides-aside-width) - 32px); + &.drag { + app-slide-thumbnail { + transition: margin 0.25s ease-out, min-height 0.25s ease-in; + } + } + app-slide-thumbnail { margin-bottom: 16px; - transition: margin 0.25s ease-out, min-height 0.25s ease-in; + transition: margin 0.15s ease-in; &.hover { margin-bottom: calc((var(--slides-aside-width) - 32px) * 9 / 16); } + &.hover-top { + margin-top: calc((var(--slides-aside-width) - 32px) * 9 / 16); + } + &.drag-start, &.drag-hover { visibility: hidden; opacity: 0; diff --git a/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.tsx b/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.tsx index 8d0e2b517..ab948f143 100644 --- a/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.tsx +++ b/studio/src/app/components/editor/actions/app-slides-aside/app-slides-aside.tsx @@ -81,8 +81,6 @@ export class AppSlidesAside { to: undefined, complete: () => {} }; - - console.log(this.reorderDetail); } private onDragHover(to: number) { @@ -96,6 +94,21 @@ export class AppSlidesAside { }; } + private onDragLeave() { + if (!this.reorderDetail) { + return; + } + + if (this.reorderDetail.to !== 0) { + return; + } + + this.reorderDetail = { + ...this.reorderDetail, + to: -1 + }; + } + private onDrop() { if (!this.reorderDetail || this.reorderDetail.to === undefined) { return; @@ -118,7 +131,11 @@ export class AppSlidesAside { render() { return ( - this.onDrop()} onDragOver={($event: DragEvent) => $event.preventDefault()}> + this.onDrop()} + onDragOver={($event: DragEvent) => $event.preventDefault()} + onDragLeave={() => this.onDragLeave()} + class={this.reorderDetail !== undefined ? 'drag' : ''}> {this.slides.map((slide: HTMLElement, index: number) => ( ) { - console.log($event); - if (!$event || !$event.detail) { return; } From 282d0a92d7d2aad39f44296fd90a37be72b736a5 Mon Sep 17 00:00:00 2001 From: peterpeterparker Date: Wed, 18 Aug 2021 17:58:53 +0200 Subject: [PATCH 4/4] style: align thumbnails and actions --- .../actions/footer/app-actions-editor/app-actions-editor.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/src/app/components/editor/actions/footer/app-actions-editor/app-actions-editor.scss b/studio/src/app/components/editor/actions/footer/app-actions-editor/app-actions-editor.scss index 030e41d77..98dbd5193 100644 --- a/studio/src/app/components/editor/actions/footer/app-actions-editor/app-actions-editor.scss +++ b/studio/src/app/components/editor/actions/footer/app-actions-editor/app-actions-editor.scss @@ -50,7 +50,7 @@ app-actions-editor { aside { height: 100%; - padding: 16px 0; + padding: 8px 0; display: flex; flex-direction: column;