From 035f488fa239d8986f43261767080694d448eb07 Mon Sep 17 00:00:00 2001 From: peterpeterparker Date: Thu, 19 Aug 2021 08:39:52 +0200 Subject: [PATCH 01/11] feat: add slide button at the bottom of the thumbnails --- .../app-slides-aside/app-slides-aside.scss | 94 +++++++++++++------ .../app-slides-aside/app-slides-aside.tsx | 24 ++++- .../app-actions-editor.scss | 33 ++----- studio/src/global/theme/mixins/_button.scss | 31 ++++++ 4 files changed, 126 insertions(+), 56 deletions(-) create mode 100644 studio/src/global/theme/mixins/_button.scss 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 3eab63e92..d6cc8538b 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 @@ -1,45 +1,85 @@ +@use "../../../../../global/theme/mixins/button"; + app-slides-aside { - display: flex; - flex-direction: column; - min-height: 100%; - height: 100%; + position: relative; + + aside { + display: flex; + flex-direction: column; + + min-height: 100%; + height: 100%; - width: var(--slides-aside-width); + width: var(--slides-aside-width); - padding: 16px; - overflow: scroll; - border-right: 1px solid #dedede; + padding: 16px 16px 48px; + overflow: scroll; + border-right: 1px solid #dedede; - --preview-width: calc(var(--slides-aside-width) - 32px); + --preview-width: calc(var(--slides-aside-width) - 32px); + + &.drag { + app-slide-thumbnail { + transition: margin 0.25s ease-out, min-height 0.25s ease-in; + } + } - &.drag { app-slide-thumbnail { - transition: margin 0.25s ease-out, min-height 0.25s ease-in; + margin-bottom: 16px; + + 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; + } + + &.drag-hover { + min-height: 0; + border: none; + } } } - app-slide-thumbnail { - margin-bottom: 16px; + div.actions { + position: absolute; + bottom: 0; + left: 0; - transition: margin 0.15s ease-in; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; - &.hover { - margin-bottom: calc((var(--slides-aside-width) - 32px) * 9 / 16); - } + width: 100%; - &.hover-top { - margin-top: calc((var(--slides-aside-width) - 32px) * 9 / 16); - } + background: var(--ion-color-light); + border: 1px solid #dedede; - &.drag-start, &.drag-hover { - visibility: hidden; - opacity: 0; - } + padding: 8px 16px; + } + + app-action-add-slide { + button { + --button-action-flex-direction: row; + + @include button.action; + + ion-icon { + @include button.icon; - &.drag-hover { - min-height: 0; - border: none; + font-size: 14px; + margin: 0 4px 0 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 ab948f143..f3464c80c 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 @@ -131,7 +131,17 @@ export class AppSlidesAside { render() { return ( - + {this.renderSlides()} + + + + ); + } + + private renderSlides() { + return ( + + ); + } + + private renderActions() { + return ( +
+ +
); } } 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 98dbd5193..1c73b4d31 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 @@ -1,3 +1,5 @@ +@use "../../../../../../global/theme/mixins/button"; + app-actions-editor { background: transparent; display: block; @@ -13,36 +15,16 @@ app-actions-editor { } button { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - padding: 0 12px; + @include button.action; - position: relative; - - outline: none; - - color: inherit; - - border-radius: 2px; - background: transparent; - - &:focus { - background: rgba(var(--ion-color-medium-rgb), 0.1); + ion-label { + margin-bottom: 6px; } ion-icon { font-size: 22px; margin: 6px 0 4px; } - - ion-label { - font-size: var(--font-size-small); - margin-bottom: 6px; - white-space: nowrap; - } } } @@ -69,10 +51,7 @@ app-actions-editor { padding: 2px 12px; ion-icon { - padding: 6px; - border-radius: 50%; - background: white; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); + @include button.icon; } } } diff --git a/studio/src/global/theme/mixins/_button.scss b/studio/src/global/theme/mixins/_button.scss new file mode 100644 index 000000000..e77449a5e --- /dev/null +++ b/studio/src/global/theme/mixins/_button.scss @@ -0,0 +1,31 @@ +@mixin action { + display: flex; + flex-direction: var(--button-action-flex-direction, column); + justify-content: center; + align-items: center; + + position: relative; + + outline: none; + + color: inherit; + + border-radius: 2px; + background: transparent; + + &:focus { + background: rgba(var(--ion-color-medium-rgb), 0.1); + } + + ion-label { + font-size: var(--font-size-small); + white-space: nowrap; + } +} + +@mixin icon { + padding: 6px; + border-radius: 50%; + background: white; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); +} From 40180d7891bc43789c803b035297cbc0d848f283 Mon Sep 17 00:00:00 2001 From: peterpeterparker Date: Thu, 19 Aug 2021 08:44:10 +0200 Subject: [PATCH 02/11] feat: handles delete slide --- .../app-slides-aside/app-slides-aside.tsx | 17 ++++++++++++++++- .../editor/events/deck/deck-events.handler.ts | 16 +++------------- 2 files changed, 19 insertions(+), 14 deletions(-) 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 f3464c80c..b08b486c4 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 @@ -57,12 +57,27 @@ export class AppSlidesAside { this.debounceUpdateSlide(updatedSlide); } + @Listen('slideDelete', {target: 'document'}) + async onSlideDelete({detail: deletedSlide}: CustomEvent) { + await this.deleteSlide(deletedSlide); + } + private async updateSlide(updatedSlide: HTMLElement) { - const slideIndex: number = Array.from(updatedSlide.parentNode.children).indexOf(updatedSlide); + const slideIndex: number = this.slideIndex(updatedSlide); this.slides = [...this.slides.map((slide: HTMLElement, index: number) => (slideIndex === index ? (updatedSlide.cloneNode(true) as HTMLElement) : slide))]; } + private async deleteSlide(deletedSlide: HTMLElement) { + const slideIndex: number = this.slideIndex(deletedSlide); + + this.slides = [...this.slides.filter((_slide: HTMLElement, index: number) => slideIndex !== index)]; + } + + private slideIndex(slide: HTMLElement): number { + return Array.from(slide.parentNode.children).indexOf(slide); + } + private async updateAllSlides() { const slides: NodeListOf = document.querySelectorAll(`${deckSelector} > *`); diff --git a/studio/src/app/handlers/editor/events/deck/deck-events.handler.ts b/studio/src/app/handlers/editor/events/deck/deck-events.handler.ts index 5d9407d46..f32f4da5a 100644 --- a/studio/src/app/handlers/editor/events/deck/deck-events.handler.ts +++ b/studio/src/app/handlers/editor/events/deck/deck-events.handler.ts @@ -559,19 +559,9 @@ export class DeckEventsHandler { }); } - private deleteSlideElement(): Promise { - return new Promise(async (resolve) => { - const deck: HTMLElement = this.mainRef.querySelector('deckgo-deck'); - - if (!deck) { - resolve(); - return; - } - - await (deck as any).deleteActiveSlide(); - - resolve(); - }); + private async deleteSlideElement() { + const deck: HTMLDeckgoDeckElement = this.mainRef.querySelector('deckgo-deck'); + await deck?.deleteActiveSlide(); } private async getSlideAttributes(slide: HTMLElement, cleanFields: boolean): Promise { From 6b71ecd65141ad23f47bd4db204987535467437f Mon Sep 17 00:00:00 2001 From: peterpeterparker Date: Thu, 19 Aug 2021 08:53:27 +0200 Subject: [PATCH 03/11] style: ripple effect --- studio/src/global/theme/mixins/_button.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/studio/src/global/theme/mixins/_button.scss b/studio/src/global/theme/mixins/_button.scss index e77449a5e..94a8aab7b 100644 --- a/studio/src/global/theme/mixins/_button.scss +++ b/studio/src/global/theme/mixins/_button.scss @@ -10,7 +10,9 @@ color: inherit; - border-radius: 2px; + border-radius: 8px; + overflow: hidden; + background: transparent; &:focus { From d98233254f2881813301ec7028f785e5d43325a7 Mon Sep 17 00:00:00 2001 From: peterpeterparker Date: Thu, 19 Aug 2021 09:34:53 +0200 Subject: [PATCH 04/11] fix: semantic --- .../editor/actions/app-slides-aside/app-slides-aside.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 b08b486c4..b2b8e693a 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 @@ -149,7 +149,7 @@ export class AppSlidesAside { {this.renderSlides()} - + {this.renderActions()} ); } @@ -183,8 +183,6 @@ export class AppSlidesAside { onDragStart={() => this.onDragStart(index)} onDragOver={() => this.onDragHover(index)}> ))} - - {this.renderActions()} ); } From 764e6686dae12e80e99d19f4296b6e14902d8ddd Mon Sep 17 00:00:00 2001 From: peterpeterparker Date: Thu, 19 Aug 2021 10:00:58 +0200 Subject: [PATCH 05/11] feat: effectively add slide --- .../app-slides-aside/app-slides-aside.tsx | 2 +- .../app-action-add-slide.tsx | 23 +++++++--------- .../app-actions-deck/app-actions-deck.tsx | 13 +-------- .../app-actions-element.tsx | 5 ++-- .../app-actions-editor/app-actions-editor.tsx | 10 ++----- .../pages/editor/app-editor/app-editor.tsx | 5 ++-- .../style/app-deck-style/app-deck-style.tsx | 14 +++++----- .../editor/anonymous/anonymous.service.ts | 8 +++--- studio/src/components.d.ts | 27 +++++-------------- 9 files changed, 36 insertions(+), 71 deletions(-) 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 b2b8e693a..f94d61ecc 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 @@ -190,7 +190,7 @@ export class AppSlidesAside { private renderActions() { return (
- +
); } diff --git a/studio/src/app/components/editor/actions/deck/app-action-add-slide/app-action-add-slide.tsx b/studio/src/app/components/editor/actions/deck/app-action-add-slide/app-action-add-slide.tsx index 836b445fe..37f7c6301 100644 --- a/studio/src/app/components/editor/actions/deck/app-action-add-slide/app-action-add-slide.tsx +++ b/studio/src/app/components/editor/actions/deck/app-action-add-slide/app-action-add-slide.tsx @@ -1,4 +1,4 @@ -import {Component, Element, EventEmitter, h, JSX, Prop} from '@stencil/core'; +import {Component, Element, Event, EventEmitter, h, JSX, Prop} from '@stencil/core'; import {modalController, OverlayEventDetail, popoverController} from '@ionic/core'; @@ -20,16 +20,16 @@ export class AppActionAddSlide { @Element() el: HTMLElement; @Prop() - slides: JSX.IntrinsicElements[] = []; + slidesLength: number | undefined; - @Prop() - blockSlide: EventEmitter; + @Event({bubbles: true}) + private signIn: EventEmitter; - @Prop() - signIn: EventEmitter; + @Event({bubbles: true}) + private addSlide: EventEmitter; - @Prop() - addSlide: EventEmitter; + @Event({bubbles: true}) + private blockSlide: EventEmitter; private anonymousService: AnonymousService; @@ -42,7 +42,7 @@ export class AppActionAddSlide { return; } - const couldAddSlide: boolean = await this.anonymousService.couldAddSlide(this.slides); + const couldAddSlide: boolean = await this.anonymousService.couldAddSlide(this.slidesLength); if (!couldAddSlide) { this.signIn.emit(); @@ -276,10 +276,7 @@ export class AppActionAddSlide { render() { return ( - this.onActionOpenSlideAdd($event)}> + this.onActionOpenSlideAdd($event)}> ); diff --git a/studio/src/app/components/editor/actions/deck/app-actions-deck/app-actions-deck.tsx b/studio/src/app/components/editor/actions/deck/app-actions-deck/app-actions-deck.tsx index 27ef6a462..d319992af 100644 --- a/studio/src/app/components/editor/actions/deck/app-actions-deck/app-actions-deck.tsx +++ b/studio/src/app/components/editor/actions/deck/app-actions-deck/app-actions-deck.tsx @@ -30,15 +30,6 @@ export class AppActionsDeck { @Prop() slides: JSX.IntrinsicElements[] = []; - @Prop() - blockSlide: EventEmitter; - - @Prop() - signIn: EventEmitter; - - @Prop() - addSlide: EventEmitter; - @Prop() animatePrevNextSlide: EventEmitter; @@ -160,8 +151,6 @@ export class AppActionsDeck { const popover: HTMLIonPopoverElement = await popoverController.create({ component: 'app-deck-style', componentProps: { - signIn: this.signIn, - blockSlide: this.blockSlide, deckDidChange: this.deckDidChange }, mode: 'ios', @@ -240,7 +229,7 @@ export class AppActionsDeck { return ( ); } + private renderThumbnail(slide: HTMLElement, index: number) { + const dragClass: string = + index === this.reorderDetail?.to && this.reorderDetail?.from !== this.reorderDetail?.to + ? 'hover' + : index === 0 && this.reorderDetail?.to === -1 + ? 'hover-top' + : index === this.reorderDetail?.from + ? index === this.reorderDetail?.to + ? 'drag-start' + : 'drag-hover' + : ''; + + return ( + await slideTo(index)} + key={slide.getAttribute('slide_id')} + slide={slide} + deck={this.deckRef} + class={`${dragClass} ${this.activeIndex === index ? 'highlight' : ''}`} + draggable={true} + onDragStart={() => this.onDragStart(index)} + onDragOver={() => this.onDragHover(index)}> + ); + } + private renderActions() { return (
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 ba61b3e07..c76edc06a 100644 --- a/studio/src/app/pages/editor/app-editor/app-editor.tsx +++ b/studio/src/app/pages/editor/app-editor/app-editor.tsx @@ -837,7 +837,7 @@ export class AppEditor { return undefined; } - return ; + return ; } private renderSlidePreview() { diff --git a/studio/src/components.d.ts b/studio/src/components.d.ts index 5697f2169..3f917379a 100644 --- a/studio/src/components.d.ts +++ b/studio/src/components.d.ts @@ -355,6 +355,7 @@ export namespace Components { "overflow": boolean; } interface AppSlidesAside { + "activeIndex": number; "deckRef": HTMLDeckgoDeckElement; } interface AppSlotType { @@ -1680,6 +1681,7 @@ declare namespace LocalJSX { "overflow"?: boolean; } interface AppSlidesAside { + "activeIndex"?: number; "deckRef": HTMLDeckgoDeckElement; "onReorder"?: (event: CustomEvent) => void; }