Skip to content
This repository was archived by the owner on Feb 6, 2024. It is now read-only.
Merged
Original file line number Diff line number Diff line change
@@ -1,45 +1,91 @@
@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;

&.highlight {
border: 1px solid var(--ion-color-dark);
box-shadow: rgba(var(--ion-color-dark-rgb), 0.4) 0 1px 4px;
}

&.hover {
margin-bottom: calc(var(--slides-aside-width) * 9 / 16);
}

&.hover-top {
margin-top: calc(var(--slides-aside-width) * 9 / 16);
}

&.drag-start, &.drag-hover {
visibility: hidden;
opacity: 0;
}

&.drag-hover {
min-height: 0;
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;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export class AppSlidesAside {
@State()
private slides: HTMLElement[] = [];

@Prop()
activeIndex: number;

@Prop()
deckRef!: HTMLDeckgoDeckElement;

Expand All @@ -28,6 +31,9 @@ export class AppSlidesAside {

private readonly debounceUpdateSlide: (updateSlide: HTMLElement) => void;

private canDragLeave: boolean = true;
private canDragHover: boolean = true;

constructor() {
this.debounceUpdateAllSlides = debounce(async () => {
await this.updateAllSlides();
Expand All @@ -42,6 +48,13 @@ export class AppSlidesAside {
this.debounceUpdateAllSlides();
}

componentDidUpdate() {
setTimeout(() => {
this.canDragLeave = true;
this.canDragHover = true;
}, 250);
}

@Listen('deckDidLoad', {target: 'document'})
onDeckDidLoad() {
this.debounceUpdateAllSlides();
Expand All @@ -57,12 +70,27 @@ export class AppSlidesAside {
this.debounceUpdateSlide(updatedSlide);
}

@Listen('slideDelete', {target: 'document'})
async onSlideDelete({detail: deletedSlide}: CustomEvent<HTMLElement>) {
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<HTMLElement> = document.querySelectorAll(`${deckSelector} > *`);

Expand All @@ -84,17 +112,29 @@ export class AppSlidesAside {
}

private onDragHover(to: number) {
if (!this.reorderDetail) {
if (!this.canDragHover) {
return;
}

if (!this.reorderDetail || this.reorderDetail.to === to) {
return;
}

if (this.reorderDetail.to === -1 && to === 0) {
this.canDragLeave = false;
}

this.reorderDetail = {
...this.reorderDetail,
to
};
}

private onDragLeave() {
if (!this.canDragLeave) {
return;
}

if (!this.reorderDetail) {
return;
}
Expand All @@ -103,6 +143,8 @@ export class AppSlidesAside {
return;
}

this.canDragHover = false;

this.reorderDetail = {
...this.reorderDetail,
to: -1
Expand Down Expand Up @@ -131,34 +173,57 @@ export class AppSlidesAside {

render() {
return (
<Host
<Host>
{this.renderSlides()}

{this.renderActions()}
</Host>
);
}

private renderSlides() {
return (
<aside
onDrop={() => this.onDrop()}
onDragOver={($event: DragEvent) => $event.preventDefault()}
onDragLeave={() => this.onDragLeave()}
class={this.reorderDetail !== undefined ? 'drag' : ''}>
{this.slides.map((slide: HTMLElement, index: number) => (
<app-slide-thumbnail
custom-tappable
onClick={async () => await slideTo(index)}
key={slide.getAttribute('slide_id')}
slide={slide}
deck={this.deckRef}
class={
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'
: ''
}
draggable={true}
onDragStart={() => this.onDragStart(index)}
onDragOver={() => this.onDragHover(index)}></app-slide-thumbnail>
))}
</Host>
{this.slides.map((slide: HTMLElement, index: number) => this.renderThumbnail(slide, index))}
</aside>
);
}

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 (
<app-slide-thumbnail
custom-tappable
onClick={async () => 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)}></app-slide-thumbnail>
);
}

private renderActions() {
return (
<div class="actions">
<app-action-add-slide slidesLength={this.slides.length} popoverCssClass="popover-menu-wide-start"></app-action-add-slide>
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -20,16 +20,19 @@ export class AppActionAddSlide {
@Element() el: HTMLElement;

@Prop()
slides: JSX.IntrinsicElements[] = [];
slidesLength: number | undefined;

@Prop()
blockSlide: EventEmitter;
popoverCssClass: string;

@Prop()
signIn: EventEmitter;
@Event({bubbles: true})
private signIn: EventEmitter<void>;

@Prop()
addSlide: EventEmitter;
@Event({bubbles: true})
private addSlide: EventEmitter<JSX.IntrinsicElements>;

@Event({bubbles: true})
private blockSlide: EventEmitter<boolean>;

private anonymousService: AnonymousService;

Expand All @@ -42,7 +45,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();
Expand All @@ -53,7 +56,7 @@ export class AppActionAddSlide {
component: 'app-create-slide',
mode: 'ios',
showBackdrop: false,
cssClass: 'popover-menu popover-menu-wide'
cssClass: `popover-menu popover-menu-wide ${this.popoverCssClass}`
});

popover.onDidDismiss().then(async (detail: OverlayEventDetail) => {
Expand Down Expand Up @@ -276,10 +279,7 @@ export class AppActionAddSlide {

render() {
return (
<app-action-busy
aria-label={i18n.state.editor.add_slide}
iconName="add"
onActionReady={($event: CustomEvent) => this.onActionOpenSlideAdd($event)}>
<app-action-busy aria-label={i18n.state.editor.add_slide} iconName="add" onActionReady={($event: CustomEvent) => this.onActionOpenSlideAdd($event)}>
<ion-label aria-hidden="true">{i18n.state.editor.add_slide}</ion-label>
</app-action-busy>
);
Expand Down
Loading