mirror of https://github.com/Squidex/squidex.git
24 changed files with 331 additions and 64 deletions
@ -0,0 +1,16 @@ |
|||||
|
<div *sqxModalView="tooltipModal;onRoot:true" closeAlways="true" [sqxModalTarget]="for" [position]="position" [offset]="4" [auto]="false"> |
||||
|
<div class="onboarding-tooltip" [ngClass]="position"> |
||||
|
<div class="arrow1"></div> |
||||
|
<div class="arrow2"></div> |
||||
|
|
||||
|
<div class="content">{{text}}</div> |
||||
|
|
||||
|
<a (click)="hideThis()" class="hide-this btn-link btn-default btn-sm"> |
||||
|
<i class="icon-close"></i> |
||||
|
</a> |
||||
|
|
||||
|
<button (click)="hideAll()" class="hide-all btn-link btn-primary btn-sm"> |
||||
|
Hide all Tooltips |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,46 @@ |
|||||
|
@import '_mixins'; |
||||
|
@import '_vars'; |
||||
|
|
||||
|
$color: $color-theme-blue; |
||||
|
|
||||
|
$size-arrow: 10px; |
||||
|
|
||||
|
// sass-lint:disable class-name-format |
||||
|
|
||||
|
.onboarding-tooltip { |
||||
|
& { |
||||
|
@include box-shadow(0, 2px, 20px, .3); |
||||
|
max-width: 20rem; |
||||
|
background: $color-dark-foreground; |
||||
|
border: 1px solid $color; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.content { |
||||
|
padding: 1.6rem 1.6rem 2.5rem; |
||||
|
} |
||||
|
|
||||
|
.hide-this { |
||||
|
@include absolute(.1rem, .1rem, auto, auto); |
||||
|
} |
||||
|
|
||||
|
.hide-all { |
||||
|
@include absolute(auto, .1rem, .1rem, auto); |
||||
|
} |
||||
|
|
||||
|
&.topRight { |
||||
|
& { |
||||
|
margin-right: -$size-arrow - 1; |
||||
|
} |
||||
|
|
||||
|
.arrow1 { |
||||
|
@include caret-top($color, $size-arrow); |
||||
|
@include absolute(-$size-arrow * 2, $size-arrow * .5, auto, auto); |
||||
|
} |
||||
|
|
||||
|
.arrow2 { |
||||
|
@include caret-top($color-dark-foreground, $size-arrow); |
||||
|
@include absolute(-$size-arrow * 2 + 1, $size-arrow * .5, auto, auto); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,98 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import { Component, Input, OnDestroy, OnInit, Renderer } from '@angular/core'; |
||||
|
|
||||
|
import { ModalView } from './../utils/modal-view'; |
||||
|
|
||||
|
import { OnboardingService } from './../services/onboarding.service'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'sqx-onboarding-tooltip', |
||||
|
styleUrls: ['./onboarding-tooltip.component.scss'], |
||||
|
templateUrl: './onboarding-tooltip.component.html' |
||||
|
}) |
||||
|
export class OnboardingTooltipComponent implements OnDestroy, OnInit { |
||||
|
private showTimer: any; |
||||
|
private closeTimer: any; |
||||
|
private forClickListener: Function; |
||||
|
|
||||
|
public tooltipModal = new ModalView(); |
||||
|
|
||||
|
@Input() |
||||
|
public for: any; |
||||
|
|
||||
|
@Input() |
||||
|
public id: string; |
||||
|
|
||||
|
@Input() |
||||
|
public position = 'left'; |
||||
|
|
||||
|
@Input() |
||||
|
public after = 1000; |
||||
|
|
||||
|
@Input() |
||||
|
public text: string; |
||||
|
|
||||
|
constructor( |
||||
|
private readonly onboardingService: OnboardingService, |
||||
|
private readonly renderer: Renderer |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public ngOnDestroy() { |
||||
|
if (this.showTimer) { |
||||
|
clearTimeout(this.showTimer); |
||||
|
this.showTimer = null; |
||||
|
} |
||||
|
|
||||
|
if (this.closeTimer) { |
||||
|
clearTimeout(this.closeTimer); |
||||
|
this.closeTimer = null; |
||||
|
} |
||||
|
|
||||
|
if (this.forClickListener) { |
||||
|
this.forClickListener(); |
||||
|
this.forClickListener = null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ngOnInit() { |
||||
|
if (this.for && this.id) { |
||||
|
this.showTimer = setTimeout(() => { |
||||
|
if (this.onboardingService.shouldShow(this.id)) { |
||||
|
this.tooltipModal.show(); |
||||
|
|
||||
|
this.closeTimer = setTimeout(() => { |
||||
|
this.hideThis(); |
||||
|
}, 10000); |
||||
|
} |
||||
|
}, this.after); |
||||
|
|
||||
|
this.forClickListener = |
||||
|
this.renderer.listen(this.for, 'mousedown', () => { |
||||
|
this.onboardingService.disable(this.id); |
||||
|
|
||||
|
this.hideThis(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public hideThis() { |
||||
|
this.onboardingService.disable(this.id); |
||||
|
this.tooltipModal.hide(); |
||||
|
|
||||
|
this.ngOnDestroy(); |
||||
|
} |
||||
|
|
||||
|
public hideAll() { |
||||
|
this.onboardingService.disableAll(); |
||||
|
this.tooltipModal.hide(); |
||||
|
|
||||
|
this.ngOnDestroy(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
|
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import { Injectable } from '@angular/core'; |
||||
|
|
||||
|
import { LocalStoreService } from './local-store.service'; |
||||
|
|
||||
|
export const OnboardingServiceFactory = (localStore: LocalStoreService) => { |
||||
|
return new OnboardingService(localStore); |
||||
|
}; |
||||
|
|
||||
|
@Injectable() |
||||
|
export class OnboardingService { |
||||
|
constructor( |
||||
|
private readonly localStore: LocalStoreService |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public disableAll() { |
||||
|
this.disable('all'); |
||||
|
} |
||||
|
|
||||
|
public disable(key: string) { |
||||
|
this.localStore.set(`squidex.onboarding.disable.${key}`, '1'); |
||||
|
} |
||||
|
|
||||
|
public shouldShow(key: string) { |
||||
|
return this.shouldShowKey(key) && this.shouldShowKey('all'); |
||||
|
} |
||||
|
|
||||
|
private shouldShowKey(key: string) { |
||||
|
return this.localStore.get(`squidex.onboarding.disable.${key}`) !== '1'; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue