@angular/animations#query TypeScript Examples
The following examples show how to use
@angular/animations#query.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: animations.ts From Angular-Cookbook with MIT License | 6 votes |
ANIMATIONS = {
LIST_ANIMATION: trigger('listAnimation', [
transition('* <=> *', [
query(
':enter',
[
style({
opacity: 0,
}),
stagger(100, [
animate(
'0.5s ease',
style({
opacity: 1,
})
),
]),
],
{ optional: true }
),
query(
':leave',
[
stagger(100, [
animate(
'0.5s ease',
style({
opacity: 0,
})
),
]),
],
{ optional: true }
),
]),
]),
}
Example #2
Source File: animations.ts From Angular-Cookbook with MIT License | 6 votes |
ANIMATIONS = {
LIST_ANIMATION: trigger('listAnimation', [
transition('* <=> *', [
query(':enter', [
style({
opacity: 0
}),
stagger(100, [
animate('0.5s ease', style({
opacity: 1
}))
])
], { optional: true }),
query(':leave', [
stagger(100, [
animate('0.5s ease', style({
opacity: 0
}))
])
], {optional: true})
]),
])
}
Example #3
Source File: helpers.ts From youpez-admin with MIT License | 6 votes |
defaultRouterTransition = trigger('defaultRouterAnimation', [
transition('* => *', [
query(
':enter',
[style({opacity: 0,})],
{optional: true}
),
query(
':leave',
[style({opacity: 1,}), animate('0.3s cubic-bezier(.785, .135, .15, .86)', style({opacity: 0}))],
{optional: true}
),
query(
':enter',
[style({opacity: 0,}), animate('0.3s cubic-bezier(.785, .135, .15, .86)', style({opacity: 1}))],
{optional: true}
)
])
])
Example #4
Source File: animations.ts From Angular-Cookbook with MIT License | 6 votes |
ROUTE_ANIMATION = trigger('routeAnimation', [
transition('* <=> *', [
style({
position: 'relative',
}),
query(
':enter, :leave',
[
style({
position: 'absolute',
width: '100%',
}),
],
{ optional: true }
),
query(
':enter',
[
style({
opacity: 0,
}),
],
{ optional: true }
),
query(':leave', [animate('300ms ease-out', style({ opacity: 0 }))], {
optional: true,
}),
query(':enter', [animate('300ms ease-in', style({ opacity: 1 }))], {
optional: true,
}),
]),
])
Example #5
Source File: animations.ts From Angular-Cookbook with MIT License | 6 votes |
ROUTE_ANIMATION = trigger('routeAnimation', [
transition('* <=> *', [
style({
position: 'relative'
}),
query(':enter, :leave', [
style({
position: 'absolute',
width: '100%',
})
], optional),
query(':enter', [
style({
opacity: 0,
})
], optional)
])
])
Example #6
Source File: animations.ts From Angular-Cookbook with MIT License | 6 votes |
ANIMATIONS = {
LIST_ANIMATION: trigger('listAnimation', [
transition('* <=> *', [
query(':enter', [
style({
opacity: 0
}),
stagger(100, [
animate('0.5s ease', style({
opacity: 1
}))
])
], { optional: true }),
query(':leave', [
stagger(100, [
animate('0.1s ease', style({
opacity: 0
}))
])
], {optional: true})
]),
])
}
Example #7
Source File: emote-list.component.ts From App with MIT License | 6 votes |
ngAfterViewInit(): void {
// Get persisted page options?
this.route.queryParamMap.pipe(
defaultIfEmpty({} as ParamMap),
map(params => {
return {
page: params.has('page') ? Number(params.get('page')) : 0,
search: {
sortBy: params.get('sortBy') ?? 'popularity',
sortOrder: params.get('sortOrder'),
globalState: params.get('globalState'),
query: params.get('query'),
submitter: params.get('submitter'),
channel: params.get('channel')
}
};
}),
tap(() => setTimeout(() => this.skipNextQueryChange = false, 0)),
filter(() => !this.skipNextQueryChange)
).subscribe({
next: opt => {
const d = {
pageIndex: !isNaN(opt.page) ? opt.page : 0,
pageSize: Math.max(EmoteListComponent.MINIMUM_EMOTES, this.calculateSizedRows() ?? 0),
length: 0,
};
this.updateQueryParams(true);
this.currentSearchOptions = opt.search as any;
this.paginator?.page.next(d);
this.pageOptions = d;
}
});
this.pageSize.next(this.calculateSizedRows() ?? 0);
}
Example #8
Source File: splash.component.ts From bitcoin-s-ts with MIT License | 6 votes |
@Component({
selector: 'splash',
templateUrl: './splash.component.html',
animations: [
// the fade-in/fade-out animation.
trigger('fadeOut', [
transition(':leave', [
query(':leave', animateChild(), {optional: true}),
animate(300, style({opacity: 0}))
]),
]),
],
styleUrls: ['./splash.component.scss']
})
export class SplashComponent implements OnInit {
showSplash = false
constructor() { }
ngOnInit(): void {
// Force reset splash key
// localStorage.removeItem(SPLASH_KEY)
const show = localStorage.getItem(SPLASH_KEY) === null
this.showSplash = show
}
dontShowSplashAgainClick() {
console.debug('dontShowSplashAgainClick()')
localStorage.setItem(SPLASH_KEY, '1')
}
onClick() {
this.showSplash = !this.showSplash
}
}
Example #9
Source File: fade.animation.ts From onchat-web with Apache License 2.0 | 6 votes |
fadeRouteAnimation = trigger('fadeRouteAnimation', [
transition('* <=> *', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%'
}),
animateChild(),
], options),
query(':enter', [
style({ opacity: 0 })
], options),
group([
query(':leave', [
animate('5s ease-in', style({ opacity: 0 }))
], options),
query(':enter', [
animate('5s ease-in', style({ opacity: 1 }))
], options)
]),
])
])
Example #10
Source File: mat-fab-menu.animations.ts From fab-menu with MIT License | 5 votes |
speedDialFabAnimations = [
trigger('fabToggler', [
state('false', style({
transform: 'rotate(0deg)'
})),
state('true', style({
transform: 'rotate(225deg)'
})),
transition('* <=> *', animate('200ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
trigger('fabsStagger', [
transition('* => *', [
query(':enter', style({opacity: 0}), {optional: true}),
query(':enter', stagger('40ms',
[
animate('200ms cubic-bezier(0.4, 0.0, 0.2, 1)',
keyframes(
[
style({opacity: 0, transform: 'translateY(10px)'}),
style({opacity: 1, transform: 'translateY(0)'}),
]
)
)
]
), {optional: true}),
query(':leave',
animate('200ms cubic-bezier(0.4, 0.0, 0.2, 1)',
keyframes([
style({opacity: 1}),
style({opacity: 0}),
])
), {optional: true}
)
])
])
]
Example #11
Source File: route.animations.ts From enterprise-ng-2020-workshop with MIT License | 5 votes |
STEPS_ALL: any[] = [
query(':enter > *', style({ opacity: 0, position: 'fixed' }), {
optional: true
}),
query(':enter .' + ROUTE_ANIMATIONS_ELEMENTS, style({ opacity: 0 }), {
optional: true
}),
sequence([
query(
':leave > *',
[
style({ transform: 'translateY(0%)', opacity: 1 }),
animate(
'0.2s ease-in-out',
style({ transform: 'translateY(-3%)', opacity: 0 })
),
style({ position: 'fixed' })
],
{ optional: true }
),
query(
':enter > *',
[
style({
transform: 'translateY(-3%)',
opacity: 0,
position: 'static'
}),
animate(
'0.5s ease-in-out',
style({ transform: 'translateY(0%)', opacity: 1 })
)
],
{ optional: true }
)
]),
query(
':enter .' + ROUTE_ANIMATIONS_ELEMENTS,
stagger(75, [
style({ transform: 'translateY(10%)', opacity: 0 }),
animate(
'0.5s ease-in-out',
style({ transform: 'translateY(0%)', opacity: 1 })
)
]),
{ optional: true }
)
]
Example #12
Source File: slide.animation.ts From onchat-web with Apache License 2.0 | 5 votes |
horizontalSlideInRouteAnimation = trigger('horizontalSlideInRouteAnimation', [
transition(':increment', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
}),
animateChild(),
], options),
query(':enter', [
style({ transform: 'translate3d(100%,0,0)' })
], options),
group([
query(':leave', [
animate('.3s ease-out', style({ transform: 'translate3d(-100%,0,0)' }))
], options),
query(':enter', [
animate('.3s ease-out', style({ transform: 'none' }))
], options)
]),
]),
transition(':decrement', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
}),
animateChild(),
], options),
query(':enter', [
style({ transform: 'translate3d(-100%,0,0)' })
], options),
group([
query(':leave', [
animate('.3s ease-out', style({ transform: 'translate3d(100%,0,0)' }))
], options),
query(':enter', [
animate('.3s ease-out', style({ transform: 'none' }))
], options)
])
])
])
Example #13
Source File: animation.ts From mns with MIT License | 5 votes |
slideInAnimation =
trigger('routeAnimations', [
transition('HomePage <=> ProductsPage', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
})
]),
query(':enter', [
style({ left: '-100%' })
]),
query(':leave', animateChild()),
group([
query(':leave', [
animate('300ms ease-out', style({ left: '100%' }))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
])
]),
query(':enter', animateChild()),
]),
transition('* <=> BlogPage', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
})
]),
query(':enter', [
style({ left: '-100%' })
]),
query(':leave', animateChild()),
group([
query(':leave', [
animate('200ms ease-out', style({ left: '100%' }))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
])
]),
query(':enter', animateChild()),
]),
transition('* <=> ContactPage', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
})
]),
query(':enter', [
style({ left: '-100%' })
]),
query(':leave', animateChild()),
group([
query(':leave', [
animate('200ms ease-out', style({ left: '100%' }))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
])
]),
query(':enter', animateChild()),
])
])
Example #14
Source File: slide.animation.ts From ng-ant-admin with MIT License | 5 votes |
horizontalSlideInRouteAnimation = trigger('horizontalSlideInRouteAnimation', [
transition(':increment', [
style({position: 'relative'}),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
}),
animateChild(),
], options),
query(':enter', [
style({transform: 'translate3d(100%,0,0)'})
], options),
group([
query(':leave', [
animate('.3s ease-out', style({transform: 'translate3d(-100%,0,0)'}))
], options),
query(':enter', [
animate('.3s ease-out', style({transform: 'none'}))
], options)
]),
]),
transition(':decrement', [
style({position: 'relative'}),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
}),
animateChild(),
], options),
query(':enter', [
style({transform: 'translate3d(-100%,0,0)'})
], options),
group([
query(':leave', [
animate('.3s ease-out', style({transform: 'translate3d(100%,0,0)'}))
], options),
query(':enter', [
animate('.3s ease-out', style({transform: 'none'}))
], options)
])
])
])
Example #15
Source File: panel.component.ts From ngx-colors with MIT License | 4 votes |
@Component({
selector: "ngx-colors-panel",
templateUrl: "./panel.component.html",
styleUrls: ["./panel.component.scss"],
animations: [
trigger("colorsAnimation", [
transition("void => slide-in", [
// Initially all colors are hidden
query(":enter", style({ opacity: 0 }), { optional: true }),
//slide-in animation
query(
":enter",
stagger("10ms", [
animate(
".3s ease-in",
keyframes([
style({ opacity: 0, transform: "translatex(-50%)", offset: 0 }),
style({
opacity: 0.5,
transform: "translatex(-10px) scale(1.1)",
offset: 0.3,
}),
style({ opacity: 1, transform: "translatex(0)", offset: 1 }),
])
),
]),
{ optional: true }
),
]),
//popup animation
transition("void => popup", [
query(":enter", style({ opacity: 0, transform: "scale(0)" }), {
optional: true,
}),
query(
":enter",
stagger("10ms", [
animate(
"500ms ease-out",
keyframes([
style({ opacity: 0.5, transform: "scale(.5)", offset: 0.3 }),
style({ opacity: 1, transform: "scale(1.1)", offset: 0.8 }),
style({ opacity: 1, transform: "scale(1)", offset: 1 }),
])
),
]),
{ optional: true }
),
]),
]),
],
})
export class PanelComponent implements OnInit {
@HostListener("document:mousedown", ["$event"])
click(event) {
if (this.isOutside(event)) {
this.emitClose("cancel");
}
}
@HostListener("document:scroll")
onScroll() {
this.onScreenMovement();
}
@HostListener("window:resize")
onResize() {
this.onScreenMovement();
}
@HostBinding("style.top.px") public top: number;
@HostBinding("style.left.px") public left: number;
@ViewChild("dialog") panelRef: ElementRef;
constructor(
public service: ConverterService,
private cdr: ChangeDetectorRef
) {}
public color = "#000000";
public previewColor: string = "#000000";
public hsva = new Hsva(0, 1, 1, 1);
public colorsAnimationEffect = "slide-in";
public palette = defaultColors;
public variants = [];
public colorFormats = formats;
public format: ColorFormats = ColorFormats.HEX;
public canChangeFormat: boolean = true;
public menu = 1;
public hideColorPicker: boolean = false;
public hideTextInput: boolean = false;
public acceptLabel: string;
public cancelLabel: string;
public colorPickerControls: "default" | "only-alpha" | "no-alpha" = "default";
private triggerInstance: NgxColorsTriggerDirective;
private TriggerBBox;
public isSelectedColorInPalette: boolean;
public indexSeleccionado;
public positionString;
public temporalColor;
public backupColor;
public ngOnInit() {
this.setPosition();
this.hsva = this.service.stringToHsva(this.color);
this.indexSeleccionado = this.findIndexSelectedColor(this.palette);
}
public ngAfterViewInit() {
this.setPositionY();
}
private onScreenMovement() {
this.setPosition();
this.setPositionY();
if (!this.panelRef.nativeElement.style.transition) {
this.panelRef.nativeElement.style.transition = "transform 0.5s ease-out";
}
}
private findIndexSelectedColor(colors): number {
let resultIndex = undefined;
if (this.color) {
for (let i = 0; i < colors.length; i++) {
const color = colors[i];
if (typeof color == "string") {
if (
this.service.stringToFormat(this.color, ColorFormats.HEX) ==
this.service.stringToFormat(color, ColorFormats.HEX)
) {
resultIndex = i;
}
} else {
if (this.findIndexSelectedColor(color.variants) != undefined) {
resultIndex = i;
}
}
}
}
return resultIndex;
}
public iniciate(
triggerInstance: NgxColorsTriggerDirective,
triggerElementRef,
color,
palette,
animation,
format: string,
hideTextInput: boolean,
hideColorPicker: boolean,
acceptLabel: string,
cancelLabel: string,
colorPickerControls: "default" | "only-alpha" | "no-alpha",
position: "top" | "bottom"
) {
this.colorPickerControls = colorPickerControls;
this.triggerInstance = triggerInstance;
this.TriggerBBox = triggerElementRef;
this.color = color;
this.hideColorPicker = hideColorPicker;
this.hideTextInput = hideTextInput;
this.acceptLabel = acceptLabel;
this.cancelLabel = cancelLabel;
if (format) {
if (formats.includes(format)) {
this.format = formats.indexOf(format.toLowerCase());
this.canChangeFormat = false;
if (
this.service.getFormatByString(this.color) != format.toLowerCase()
) {
this.setColor(this.service.stringToHsva(this.color));
}
} else {
console.error("Format provided is invalid, using HEX");
this.format = ColorFormats.HEX;
}
} else {
this.format = formats.indexOf(this.service.getFormatByString(this.color));
}
this.previewColor = this.color;
this.palette = palette ?? defaultColors;
this.colorsAnimationEffect = animation;
if (position == "top") {
let TriggerBBox = this.TriggerBBox.nativeElement.getBoundingClientRect();
this.positionString =
"transform: translateY(calc( -100% - " + TriggerBBox.height + "px ))";
}
}
public setPosition(): void {
if (this.TriggerBBox) {
const panelWidth = 250;
const viewportOffset = this.TriggerBBox.nativeElement.getBoundingClientRect();
this.top = viewportOffset.top + viewportOffset.height;
if (viewportOffset.left + panelWidth > window.innerWidth) {
this.left = viewportOffset.right < panelWidth ? window.innerWidth / 2 - panelWidth / 2 : viewportOffset.right - panelWidth;
} else {
this.left = viewportOffset.left;
}
}
}
private setPositionY(): void {
const triggerBBox = this.TriggerBBox.nativeElement.getBoundingClientRect();
const panelBBox = this.panelRef.nativeElement.getBoundingClientRect();
const panelHeight = panelBBox.height;
// Check for space below the trigger
if (triggerBBox.bottom + panelHeight > window.innerHeight) {
// there is no space, move panel over the trigger
this.positionString =
triggerBBox.top < panelBBox.height
? 'transform: translateY(-' + triggerBBox.bottom + 'px );'
: 'transform: translateY(calc( -100% - ' + triggerBBox.height + 'px ));';
} else {
this.positionString = '';
}
this.cdr.detectChanges();
}
public hasVariant(color): boolean {
if (!this.previewColor) {
return false;
}
return (
typeof color != "string" &&
color.variants.some(
(v) => v.toUpperCase() == this.previewColor.toUpperCase()
)
);
}
public isSelected(color) {
if (!this.previewColor) {
return false;
}
return (
typeof color == "string" &&
color.toUpperCase() == this.previewColor.toUpperCase()
);
}
public getBackgroundColor(color) {
if (typeof color == "string") {
return { background: color };
} else {
return { background: color?.preview };
}
}
public onAlphaChange(event) {
this.palette = this.ChangeAlphaOnPalette(event, this.palette);
}
private ChangeAlphaOnPalette(
alpha,
colors: Array<string | NgxColor>
): Array<any> {
var result = [];
for (let i = 0; i < colors.length; i++) {
const color = colors[i];
if (typeof color == "string") {
let newColor = this.service.stringToHsva(color);
newColor.onAlphaChange(alpha);
result.push(this.service.toFormat(newColor, this.format));
} else {
let newColor = new NgxColor();
let newColorPreview = this.service.stringToHsva(color.preview);
newColorPreview.onAlphaChange(alpha);
newColor.preview = this.service.toFormat(newColorPreview, this.format);
newColor.variants = this.ChangeAlphaOnPalette(alpha, color.variants);
result.push(newColor);
}
}
return result;
}
/**
* Change color from default colors
* @param string color
*/
public changeColor(color: string): void {
this.setColor(this.service.stringToHsva(color));
// this.triggerInstance.onChange();
this.emitClose("accept");
}
public onChangeColorPicker(event: Hsva) {
this.temporalColor = event;
this.color = this.service.toFormat(event, this.format);
// this.setColor(event);
this.triggerInstance.sliderChange(
this.service.toFormat(event, this.format)
);
}
public changeColorManual(color: string): void {
this.previewColor = color;
this.color = color;
this.hsva = this.service.stringToHsva(color);
this.triggerInstance.setColor(this.color);
// this.triggerInstance.onChange();
}
setColor(value: Hsva) {
this.hsva = value;
this.color = this.service.toFormat(value, this.format);
this.setPreviewColor(value);
this.triggerInstance.setColor(this.color);
}
setPreviewColor(value: Hsva) {
this.previewColor = this.service.hsvaToRgba(value).toString();
}
hsvaToRgba;
onChange() {
// this.triggerInstance.onChange();
}
public onColorClick(color) {
if (typeof color == "string") {
this.changeColor(color);
} else {
this.variants = color.variants;
this.menu = 2;
}
}
public addColor() {
this.menu = 3;
this.backupColor = this.color;
this.color = "#FF0000";
this.temporalColor = this.service.stringToHsva(this.color);
}
public nextFormat() {
if (this.canChangeFormat) {
this.format = (this.format + 1) % this.colorFormats.length;
this.setColor(this.hsva);
}
}
public emitClose(status: "cancel" | "accept") {
if (this.menu == 3) {
if (status == "cancel") {
} else if (status == "accept") {
this.setColor(this.temporalColor);
}
}
this.triggerInstance.close();
}
public onClickBack() {
if (this.menu == 3) {
this.color = this.backupColor;
this.hsva = this.service.stringToHsva(this.color);
}
this.indexSeleccionado = this.findIndexSelectedColor(this.palette);
this.menu = 1;
}
isOutside(event) {
return event.target.classList.contains("ngx-colors-overlay");
}
}
Example #16
Source File: emote-list.component.ts From App with MIT License | 4 votes |
@Component({
selector: 'app-emote-list',
templateUrl: './emote-list.component.html',
styleUrls: ['./emote-list.component.scss'],
styles: ['.selected-emote-card { opacity: 0 }'],
animations: [
trigger('fadeout', [
state('true', style({ transform: 'translateY(200%)', opacity: 0 })),
transition('* => true', animate('100ms'))
]),
trigger('emotes', [
transition('* => *', [
query('.is-emote-card:enter', [
style({ opacity: 0, transform: 'translateX(0.5em) translateY(-0.5em)', position: 'relative' }),
stagger(-4, [
animate('275ms ease-in-out', keyframes([
style({ opacity: 0, offset: 0.475 }),
style({ opacity: 1, transform: 'none', offset: 1 })
]))
])
], { optional: true }),
group([
query('.is-emote-card:not(.selected-emote-card):leave', [
style({ opacity: 1 }),
stagger(2, [
animate('100ms', style({ transform: 'scale(0)' }))
])
], { optional: true }),
query('.selected-emote-card', [
style({ opacity: 1 }),
animate('550ms', keyframes([
style({ offset: 0, opacity: 1, transform: 'scale(1)' }),
style({ offset: .2, transform: 'scale(.91)' }),
style({ offset: .38, transform: 'scale(.64)' }),
style({ offset: .44, transform: 'scale(.82)' }),
style({ offset: 1, transform: 'scale(12) translateY(25%)', opacity: 0 })
])),
], { optional: true })
])
])
])
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EmoteListComponent implements AfterViewInit, OnDestroy {
destroyed = new Subject<any>().pipe(take(1)) as Subject<void>;
selecting = new BehaviorSubject(false).pipe(takeUntil(this.destroyed)) as BehaviorSubject<boolean>;
emotes = new BehaviorSubject<any>([]).pipe(takeUntil(this.destroyed)) as BehaviorSubject<EmoteStructure[]>;
newPage = new Subject();
loading = new Subject();
totalEmotes = new BehaviorSubject<number>(0);
resized = new Subject<[number, number]>();
@ViewChild('emotesContainer') emotesContainer: ElementRef<HTMLDivElement> | undefined;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator | undefined;
@ViewChild('contextMenu') contextMenu: ContextMenuComponent | undefined;
pageOptions: EmoteListComponent.PersistentPageOptions | undefined;
pageSize = new BehaviorSubject<number>(16);
currentSearchOptions: RestV2.GetEmotesOptions | undefined;
currentSearchQuery = '';
skipNextQueryChange = false;
firstPageEvent = true;
constructor(
private restService: RestService,
private renderer: Renderer2,
private router: Router,
private route: ActivatedRoute,
private appService: AppService,
private dataService: DataService,
public themingService: ThemingService
) { }
selectEmote(ev: MouseEvent, el: any, emote: EmoteStructure): void {
if (!emote.getID()) return undefined;
ev.preventDefault();
this.selecting.next(true);
this.renderer.addClass(el, 'selected-emote-card');
this.emotes.next([]);
setTimeout(() => {
this.router.navigate(['emotes', emote.getID()]);
}, 775);
}
private updateQueryParams(replaceUrl: boolean = false): void {
const merged = {
...this.currentSearchOptions,
...{ page: (this.pageOptions?.pageIndex ?? 0) }
};
this.skipNextQueryChange = true;
this.router.navigate(['.'], {
relativeTo: this.route,
queryParams: Object.keys(merged).map(k => ({ [k]: (merged as any)[k as any] })).reduce((a, b) => ({ ...a, ...b })),
queryParamsHandling: 'merge',
replaceUrl
});
}
handleSearchChange(change: Partial<RestV2.GetEmotesOptions>): void {
const queryString = Object.keys(change).map(k => `${k}=${change[k as keyof RestV2.GetEmotesOptions]}`).join('&');
this.appService.pushTitleAttributes({ name: 'SearchOptions', value: `- ${queryString}` });
this.currentSearchOptions = { ...this.currentSearchOptions, ...change as RestV2.GetEmotesOptions };
this.updateQueryParams();
this.goToFirstPage();
this.getEmotes(undefined, this.currentSearchOptions).pipe(
delay(50),
tap(emotes => this.emotes.next(emotes))
).subscribe();
}
getEmotes(page = 0, options?: Partial<RestV2.GetEmotesOptions>): Observable<EmoteStructure[]> {
this.emotes.next([]);
this.newPage.next(page);
const timeout = setTimeout(() => this.loading.next(true), 1000);
const cancelSpinner = () => {
this.loading.next(false);
clearTimeout(timeout);
};
const size = this.calculateSizedRows();
return this.restService.awaitAuth().pipe(
switchMap(() => this.restService.v2.SearchEmotes(
(this.pageOptions?.pageIndex ?? 0) + 1,
Math.max(EmoteListComponent.MINIMUM_EMOTES, size ?? EmoteListComponent.MINIMUM_EMOTES),
options ?? this.currentSearchOptions
)),
takeUntil(this.newPage.pipe(take(1))),
tap(res => this.totalEmotes.next(res?.total_estimated_size ?? 0)),
delay(200),
map(res => res?.emotes ?? []),
mergeAll(),
map(data => this.dataService.add('emote', data)[0]),
toArray(),
defaultIfEmpty([] as EmoteStructure[]),
tap(() => cancelSpinner()),
catchError(() => defer(() => cancelSpinner()))
) as Observable<EmoteStructure[]>;
}
onOpenCardContextMenu(emote: EmoteStructure): void {
if (!this.contextMenu) {
return undefined;
}
this.contextMenu.contextEmote = emote;
emote.getOwner().pipe(
tap(usr => !!this.contextMenu ? this.contextMenu.contextUser = (usr ?? null) : noop())
).subscribe();
}
goToFirstPage(): void {
this.paginator?.page.next({
pageIndex: 0,
pageSize: this.pageOptions?.pageSize ?? 0,
length: this.pageOptions?.length ?? 0,
});
}
/**
* Handle pagination changes
*/
onPageEvent(ev: PageEvent): void {
this.pageOptions = {
...ev
};
if (this.firstPageEvent) {
this.updateQueryParams(true);
this.firstPageEvent = false;
}
else {
this.updateQueryParams();
}
// Save PageIndex title attr
this.appService.pushTitleAttributes({ name: 'PageIndex', value: `- ${ev.pageIndex}/${Number((ev.length / ev.pageSize).toFixed(0))}` });
// Fetch new set of emotes
this.getEmotes(ev.pageIndex).pipe(
tap(emotes => this.emotes.next(emotes))
).subscribe();
}
isEmpty(): Observable<boolean> {
return this.totalEmotes.pipe(
take(1),
map(size => size === 0)
);
}
/**
* Calculate how many rows and columns according to the container's size
*
* @returns the result of rows * columns
*/
calculateSizedRows(): number | null {
if (!this.emotesContainer) {
return null;
}
const marginBuffer = 28; // The margin _in pixels between each card
const cardSize = 137; // The size of the cards in pixels
const width = this.emotesContainer.nativeElement.scrollWidth - 32; // The width of emotes container
const height = this.emotesContainer.nativeElement.clientHeight - 16; // The height of the emotes container
const rows = Math.floor((width / (cardSize + marginBuffer))); // The calculated amount of rows
const columns = Math.floor(height / (cardSize + marginBuffer)); // The calculated amount of columns
// Return the result of rows multiplied by columns
return rows * columns;
}
@HostListener('window:resize', ['$event'])
onWindowResize(ev: Event): void {
const size = this.calculateSizedRows();
this.pageSize.next(size ?? 0);
this.resized.next([0, 0]);
timer(1000).pipe(
takeUntil(this.resized.pipe(take(1))),
switchMap(() => this.getEmotes(this.pageOptions?.pageIndex, {})),
tap(emotes => this.emotes.next(emotes))
).subscribe();
}
ngAfterViewInit(): void {
// Get persisted page options?
this.route.queryParamMap.pipe(
defaultIfEmpty({} as ParamMap),
map(params => {
return {
page: params.has('page') ? Number(params.get('page')) : 0,
search: {
sortBy: params.get('sortBy') ?? 'popularity',
sortOrder: params.get('sortOrder'),
globalState: params.get('globalState'),
query: params.get('query'),
submitter: params.get('submitter'),
channel: params.get('channel')
}
};
}),
tap(() => setTimeout(() => this.skipNextQueryChange = false, 0)),
filter(() => !this.skipNextQueryChange)
).subscribe({
next: opt => {
const d = {
pageIndex: !isNaN(opt.page) ? opt.page : 0,
pageSize: Math.max(EmoteListComponent.MINIMUM_EMOTES, this.calculateSizedRows() ?? 0),
length: 0,
};
this.updateQueryParams(true);
this.currentSearchOptions = opt.search as any;
this.paginator?.page.next(d);
this.pageOptions = d;
}
});
this.pageSize.next(this.calculateSizedRows() ?? 0);
}
ngOnDestroy(): void {
this.loading.complete();
}
}
Example #17
Source File: animations.ts From Angular-Cookbook with MIT License | 4 votes |
ROUTE_ANIMATION = trigger('routeAnimation', [
transition('* <=> *', [
style({
position: 'relative',
perspective: '1000px',
}),
query(
':enter, :leave',
[
style({
position: 'absolute',
width: '100%',
}),
],
optional
),
query(
':enter',
[
style({
opacity: 0,
}),
],
optional
),
group([
query(
':leave',
[
animate(
'1s ease-in',
keyframes([
style({
opacity: 1,
offset: 0,
transform: 'rotateY(0) translateX(0) translateZ(0)',
}),
style({
offset: 0.25,
transform:
'rotateY(45deg) translateX(25%) translateZ(100px) translateY(5%)',
}),
style({
offset: 0.5,
transform:
'rotateY(90deg) translateX(75%) translateZ(400px) translateY(10%)',
}),
style({
offset: 0.75,
transform:
'rotateY(135deg) translateX(75%) translateZ(800px) translateY(15%)',
}),
style({
opacity: 0,
offset: 1,
transform:
'rotateY(180deg) translateX(0) translateZ(1200px) translateY(25%)',
}),
])
),
],
optional
),
query(
':enter',
[
animate(
'1s ease-out',
keyframes([
style({
opacity: 0,
offset: 0,
transform: 'rotateY(180deg) translateX(25%) translateZ(1200px)',
}),
style({
offset: 0.25,
transform:
'rotateY(225deg) translateX(-25%) translateZ(1200px)',
}),
style({
offset: 0.5,
transform: 'rotateY(270deg) translateX(-50%) translateZ(400px)',
}),
style({
offset: 0.75,
transform: 'rotateY(315deg) translateX(-50%) translateZ(25px)',
}),
style({
opacity: 1,
offset: 1,
transform: 'rotateY(360deg) translateX(0) translateZ(0)',
}),
])
),
],
optional
),
]),
]),
])
Example #18
Source File: project-navigation.component.ts From taiga-front-next with GNU Affero General Public License v3.0 | 4 votes |
@Component({
selector: 'tg-project-navigation',
templateUrl: './project-navigation.component.html',
styleUrls: ['./project-navigation.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [
trigger('openCollapse', [
transition('open => collapsed', [
query('[data-animation="text"]', style({ opacity: 1 })),
query(':self', style({ width: '200px' })),
query('[data-animation="text"]', animate(100, style({ opacity: 0 }))),
query(':self', animate(300, style({ width: '48px' }))),
]),
transition('collapsed => open', [
query(':self', style({ width: '48px' })),
query(':self', animate(300, style({ width: '200px' }))),
]),
]),
],
})
export class ProjectNavigationComponent implements OnChanges, OnInit {
@Input()
public project: Project;
@Output()
public search = new EventEmitter();
public videoUrl: string | null;
public scrumVisible = false;
public collapseText = true;
public section!: string;
public dialog: ProjectMenuDialog = {
open: false,
hover: false,
mainLinkHeight: 0,
isSearch: false,
type: '',
slug: '',
top: 0,
left: 0,
text: '',
height: 0,
children: [],
};
public milestoneId$: Observable<Milestone['id'] | undefined | null>;
@HostBinding('class.collapsed')
public collapsed = false;
private dialogCloseTimeout?: number;
@HostBinding('@openCollapse') get openCollapseAnimation() {
return this.collapsed ? 'collapsed' : 'open';
}
@HostListener('@openCollapse.done') animationDone() {
this.collapseText = this.collapsed ? true : false;
}
constructor(
private readonly translateService: TranslateService,
private readonly cd: ChangeDetectorRef,
private readonly legacyService: LegacyService,
private readonly router: Router) {}
public ngOnInit() {
this.collapsed = (localStorage.getItem('projectnav-collapsed') === 'true');
this.section = this.getActiveSection();
// LEGACY
this.milestoneId$ = this.legacyService.legacyState
.pipe(
pluck('detailObj'),
map((obj) => {
return obj?.milestone;
})
);
if (this.section === 'backlog') {
this.scrumVisible = (localStorage.getItem('projectnav-scrum') === 'true');
}
}
public getActiveSection() {
const { breadcrumb, sectionName } = this.getSection();
const indexBacklog = breadcrumb.lastIndexOf('backlog');
const indexKanban = breadcrumb.lastIndexOf('kanban');
let oldSectionName = '';
if (indexBacklog !== -1 || indexKanban !== -1) {
if (indexKanban === -1 || indexBacklog > indexKanban) {
oldSectionName = 'backlog';
} else {
oldSectionName = 'kanban';
}
}
// task & us the sectionName is backlog-kanban
if (sectionName === 'backlog-kanban') {
if (['backlog', 'kanban'].includes(oldSectionName)) {
return oldSectionName;
} else if (this.project.isBacklogActivated && !this.project.isKanbanActivated) {
return 'backlog';
} else if (!this.project.isBacklogActivated && this.project.isKanbanActivated) {
return 'kanban';
}
}
return sectionName;
}
public popup(event: MouseEvent, type: string) {
if (!this.collapsed) {
return;
}
this.initDialog(event.target as HTMLElement, type);
this.dialog.type = type;
}
public popupScrum(event: MouseEvent) {
if (!this.collapsed) {
return;
}
const children: ProjectMenuDialog['children'] = this.milestones.map((milestone) => {
return {
text: milestone.name,
link: ['/project', this.project.slug, 'taskboard', milestone.slug],
};
});
children.unshift({
text: this.translateService.instant('PROJECT.SECTION.BACKLOG'),
link: ['/project', this.project.slug, 'backlog'],
});
this.initDialog(event.target as HTMLElement, 'scrum', children);
}
public get milestones() {
return this.project.milestones
.filter((milestone) => !milestone.closed)
.reverse()
.slice(0, 7);
}
public initDialog(el: HTMLElement, type: string, children: ProjectMenuDialog['children'] = []) {
if (this.dialogCloseTimeout) {
clearTimeout(this.dialogCloseTimeout);
}
const text = el.querySelector('.menu-option-text')?.innerHTML;
if (text) {
const link = el.querySelector('a')?.getAttribute('href');
if (link) {
this.dialog.slug = link;
} else {
this.dialog.slug = '';
}
const navigationBarWidth = 48;
this.dialog.hover = false;
this.dialog.mainLinkHeight = el.offsetHeight;
this.dialog.left = navigationBarWidth;
this.dialog.top = el.offsetTop;
this.dialog.open = true;
this.dialog.text = text;
this.dialog.children = children;
this.dialog.type = type;
}
}
public out() {
this.dialogCloseTimeout = setTimeout(() => {
if (!this.dialog.hover) {
this.dialog.open = false;
this.dialog.type = '';
this.cd.markForCheck();
}
}, 100);
}
public enterDialog() {
this.dialog.open = true;
this.dialog.hover = true;
}
public outDialog() {
this.dialog.hover = false;
this.out();
}
public ngOnChanges(changes: SimpleChanges) {
if (changes.project) {
this.videoUrl = this.videoConferenceUrl();
}
}
get isMenuEpicsEnabled() {
return this.project.isEpicsActivated && this.project.myPermissions.includes(Permissions.viewEpics);
}
get isMenuScrumEnabled() {
return this.project.isBacklogActivated && this.project.myPermissions.includes(Permissions.viewUserstory);
}
get isMenuKanbanEnabled() {
return this.project.isKanbanActivated && this.project.myPermissions.includes(Permissions.viewUserstory);
}
get isMenuIssuesEnabled() {
return this.project.isIssuesActivated && this.project.myPermissions.includes(Permissions.viewIssues);
}
get isMenuWikiEnabled() {
return this.project.isWikiActivated && this.project.myPermissions.includes(Permissions.viewWikiPages);
}
public toggleScrum() {
if (this.collapsed) {
this.router.navigate(['/project', this.project.slug, 'backlog']);
} else {
this.scrumVisible = !this.scrumVisible;
localStorage.setItem('projectnav-scrum', String(this.scrumVisible));
}
}
public toggleCollapse() {
this.collapsed = !this.collapsed;
localStorage.setItem('projectnav-collapsed', String(this.collapsed));
if (this.collapsed) {
this.scrumVisible = false;
}
}
private videoConferenceUrl(): string | null {
let baseUrl = '';
if (!this.project.videoconferences) {
return null;
}
if (this.project.videoconferences === 'whereby-com') {
baseUrl = 'https://whereby.com/';
} else if (this.project.videoconferences === 'talky') {
baseUrl = 'https://talky.io/';
} else if (this.project.videoconferences === 'jitsi') {
baseUrl = 'https://meet.jit.si/';
} else if (this.project.videoconferences === 'custom' && this.project.videoconferencesExtraData) {
return this.project.videoconferencesExtraData;
}
let url = '';
// Add prefix to the chat room name if exist
if (this.project.videoconferencesExtraData) {
url = `${this.project.slug}-${UtilsService.slugify(this.project.videoconferencesExtraData)}`;
} else {
url = this.project.slug;
}
// Some special cases
if (this.project.videoconferences === 'jitsi') {
url = url.replace(/-/g, '');
}
return baseUrl + url;
}
// LEGACY
private getSection() {
const injector = this.legacyService.getInjector();
const projectService = injector.get('tgProjectService');
return {
breadcrumb: projectService.sectionsBreadcrumb.toJS(),
sectionName: projectService.section,
};
}
}