Skip to content
Snippets Groups Projects
Commit 5eb8e22e authored by Xiao Gui's avatar Xiao Gui
Browse files

feat: added fast forward to quick tour

feat: added key navigation
chore: added quicktour cleanup on destroy
parent f322f179
No related branches found
No related tags found
No related merge requests found
......@@ -9,21 +9,6 @@ import { LOCAL_STORAGE_CONST } from "src/util/constants";
import { MatDialog, MatDialogRef } from "@angular/material/dialog";
import { StartTourDialogDialog } from "src/ui/quickTour/startTourDialog/startTourDialog.component";
export function findInLinkedList<T extends object>(first: IDoublyLinkedItem<T>, predicate: (linkedObj: IDoublyLinkedItem<T>) => boolean): IDoublyLinkedItem<T>{
let compareObj = first,
returnObj: IDoublyLinkedItem<T> = null
do {
if (predicate(compareObj)) {
returnObj = compareObj
break
}
compareObj = compareObj.next
} while(!!compareObj)
return returnObj
}
@Injectable()
export class QuickTourService {
......@@ -129,15 +114,27 @@ export class QuickTourService {
}
public nextSlide() {
if (!this.currActiveSlide.next) return
this.currActiveSlide = this.currActiveSlide.next
this.currentTip$.next(this.currActiveSlide)
}
public previousSlide() {
if (!this.currActiveSlide.prev) return
this.currActiveSlide = this.currActiveSlide.prev
this.currentTip$.next(this.currActiveSlide)
}
public ff(index: number) {
try {
const slide = this.slides.get(index)
this.currActiveSlide = slide
this.currentTip$.next(slide)
} catch (_e) {
console.warn(`cannot find slide with index ${index}`)
}
}
changeDetected(dir: QuickTourThis) {
if (this.currActiveSlide?.thisObj === dir) {
this.detectChanges$.next(null)
......
import {
Component,
ElementRef,
HostListener,
OnDestroy,
SecurityContext,
TemplateRef,
ViewChild,
} from "@angular/core";
import { combineLatest, Subscription } from "rxjs";
import { combineLatest, fromEvent, Subscription } from "rxjs";
import { QuickTourService } from "../quickTour.service";
import { debounceTime, map, shareReplay } from "rxjs/operators";
import { DomSanitizer } from "@angular/platform-browser";
......@@ -19,7 +19,7 @@ import { clamp } from "src/util/generator";
'./quickTour.style.css'
],
})
export class QuickTourComponent {
export class QuickTourComponent implements OnDestroy{
static TourCardMargin = 24
static TourCardWidthPx = 256
......@@ -33,13 +33,6 @@ export class QuickTourComponent {
public arrowTmpl: TemplateRef<any>
public arrowSrc: string
@HostListener('window:keydown', ['$event'])
keydownListener(ev: KeyboardEvent){
if (ev.key === 'Escape') {
this.quickTourService.endTour()
}
}
public tourCardTransform = `translate(-500px, -500px)`
public customArrowTransform = `translate(-500px, -500px)`
......@@ -126,10 +119,28 @@ export class QuickTourComponent {
}
this.currTip = linkedObj.thisObj
this.calculateTransforms()
}),
fromEvent(window, 'keydown', { capture: true }).subscribe((ev: KeyboardEvent) => {
if (ev.key === 'Escape') {
this.quickTourService.endTour()
}
if (ev.key === 'ArrowRight') {
this.quickTourService.nextSlide()
ev.stopPropagation()
}
if (ev.key === 'ArrowLeft') {
this.quickTourService.previousSlide()
ev.stopPropagation()
}
})
)
}
ngOnDestroy(){
while (this.subscriptions.length > 0) this.subscriptions.pop().unsubscribe()
}
nextSlide(){
this.quickTourService.nextSlide()
}
......@@ -138,6 +149,10 @@ export class QuickTourComponent {
this.quickTourService.previousSlide()
}
ff(index: number){
this.quickTourService.ff(index)
}
endTour(){
this.quickTourService.endTour()
}
......
:host
{
display: inline-flex;
width: 0px;
height: 0px;
position: relative;
display: inline-flex;
width: 0px;
height: 0px;
position: relative;
}
mat-card
{
position: absolute;
margin: 0;
z-index: 10;
position: absolute;
margin: 0;
z-index: 10;
}
.custom-svg >>> svg
......@@ -21,3 +21,13 @@ mat-card
stroke-linecap: round;
stroke-linejoin: round;
}
.progress-dot
{
transition: opacity ease-in-out 300ms;
}
.progress-dot:hover
{
opacity: 0.8!important;
}
\ No newline at end of file
......@@ -16,12 +16,14 @@
<mat-card-actions>
<button mat-icon-button
(click)="prevSlide()"
[disabled]="isFirst$ | async">
[disabled]="isFirst$ | async"
matTooltip="Previous [LEFT ARROW]">
<i class="fas fa-chevron-left"></i>
</button>
<button mat-icon-button
(click)="nextSlide()"
[disabled]="isLast$ | async">
[disabled]="isLast$ | async"
matTooltip="Next [RIGHT ARROW]">
<i class="fas fa-chevron-right"></i>
</button>
......@@ -29,7 +31,8 @@
<ng-template [ngIf]="isLast$ | async" [ngIfElse]="notLastTmpl">
<button mat-stroked-button
color="primary"
(click)="endTour()">
(click)="endTour()"
matTooltip="Dismiss [ESC]">
<i class="m-1 fas fa-check"></i>
<span>complete</span>
</button>
......@@ -37,16 +40,19 @@
<!-- dismiss (not last) -->
<ng-template #notLastTmpl>
<button mat-icon-button (click)="endTour()">
<button mat-icon-button
(click)="endTour()"
matTooltip="Dismiss [ESC]">
<i class="fas fa-times"></i>
</button>
</ng-template>
<!-- progress dots -->
<span class="muted d-inline-flex align-items-center">
<i *ngFor="let active of quickTourProgress$ | async"
<i *ngFor="let active of quickTourProgress$ | async; let index = index"
(click)="ff(index)"
[ngClass]="{ 'fa-xs muted-3': !active }"
class="ml-1 fas fa-circle"></i>
class="ml-1 fas fa-circle cursor-pointer progress-dot"></i>
</span>
</mat-card-actions>
</mat-card>
......
......@@ -85,6 +85,18 @@ export class DoublyLinkedList<T extends object>{
size(){
return this._size
}
get(idx: number) {
if (idx >= this.size()) throw new Error(`Index out of bound!`)
let i = 0
let curr = this.first
while (i < idx) {
curr = curr.next
if (!curr) throw new Error(`Index out of bound!`)
i ++
}
return curr
}
}
export function FindInLinkedList<T extends object>(list: DoublyLinkedList<T>, predicate: (element: IDoublyLinkedItem<T>) => boolean){
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment