sa-totop
Version:
A lightweight Angular standalone component for smooth scroll-to-top functionality.
195 lines (191 loc) • 9.97 kB
JavaScript
import * as i1 from '@angular/common';
import { isPlatformBrowser, CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { EventEmitter, PLATFORM_ID, Component, Inject, Input, Output } from '@angular/core';
class TotopComponent {
constructor(platformId) {
this.platformId = platformId;
this.width = 40;
this.bottom = 20;
this.end = 20;
this.color = '#0891b2';
this.scrollBehavior = 'smooth';
this.background = 'transparent';
this.duration = 0.3;
this.visibilityHeight = 450;
this.alwaysVisible = false;
this.customeBtn = false;
this.scrollComplete = new EventEmitter();
this.toTopClicked = new EventEmitter();
this.documentHieght = 0;
this.scrollHeight = 0;
this.divisionConst = 0;
this.dashOffset = 310;
this.screenHieght = 0;
}
toTop() {
if (isPlatformBrowser(this.platformId)) {
this.toTopClicked.emit();
window.scroll({
top: 0,
left: 0,
behavior: this.scrollBehavior,
});
}
}
ngOnInit() {
if (isPlatformBrowser(this.platformId)) {
this.screenHieght = window.innerHeight;
window.onscroll = () => {
this.documentHieght = document.documentElement.scrollHeight;
this.divisionConst = this.documentHieght / 310;
this.scrollHeight = document.documentElement.scrollTop;
let position = this.documentHieght - this.screenHieght - this.scrollHeight;
this.dashOffset = position / this.divisionConst;
if (this.documentHieght - 1000 < this.scrollHeight) {
this.scrollComplete.emit();
}
};
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: TotopComponent, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: TotopComponent, isStandalone: true, selector: "sa-totop", inputs: { width: "width", bottom: "bottom", end: "end", color: "color", scrollBehavior: "scrollBehavior", background: "background", duration: "duration", visibilityHeight: "visibilityHeight", alwaysVisible: "alwaysVisible", customeBtn: "customeBtn" }, outputs: { scrollComplete: "scrollComplete", toTopClicked: "toTopClicked" }, ngImport: i0, template: `
<div
(click)="toTop()"
[style]="
'--width:' +
width +
'px;' +
'--animation-time:' +
duration +
's;' +
'--color:' +
color +
';--background:' +
background +
';--bottom:' +
bottom +
'px' +
';--end:' +
end +
'px'
"
[ngClass]="{
hide: scrollHeight < visibilityHeight && !alwaysVisible,
active: documentHieght - 1000 < scrollHeight
}"
>
<ng-container *ngIf="!customeBtn">
<button>
<svg
width="100%"
height="100%"
viewBox="-1 -1 102 102"
[style]="'--progress:' + dashOffset"
>
<path d="M50,1 a49,49 0 0,1 0,98 a49,49 0 0,1 0,-98"></path>
</svg>
<svg
id="arrow"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
>
<path
fill="currentColor"
d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"
></path>
</svg>
</button>
<div></div>
</ng-container>
<ng-content></ng-content>
</div>
`, isInline: true, styles: [":host{position:relative}div{position:fixed;bottom:var(--bottom);inset-inline-end:var(--end);z-index:90;transition:.5s}div button{width:var(--width);height:var(--width);border-radius:100%;overflow:hidden;aspect-ratio:1/1;position:relative;display:flex;align-items:center;justify-content:center;color:var(--color);background-color:var(--background);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);transition:var(--animation-time)}div button:after{content:\"\";position:absolute;top:50%;left:0;transform:translate(100%,-50%) rotate(-45deg);width:calc(var(--width) * 2.2);height:calc(var(--width) / 3);transition:var(--animation-time);background:linear-gradient(288deg,white,transparent)}div button svg{position:absolute;stroke:var(--color);z-index:10;fill:none;overflow:visible;transition:var(--animation-time);stroke-width:6px;stroke-dasharray:310;stroke-dashoffset:var(--progress);stroke-linecap:round}div button #arrow{width:16px}div>div{position:absolute;width:100%;height:100%;background-color:#a1a1aa;opacity:0;transition:var(--animation-time);bottom:-25px;transform:scaleY(.1);filter:blur(10px);inset-inline-end:0px}div:hover button,div.active button{transform:translateY(-4px);background-color:var(--color);color:#fff}div:hover button:after,div.active button:after{transform:translate(100%)}div:hover button svg,div.active button svg{stroke:#fff;transform:scale(.85)}div:hover div,div.active div{opacity:.5}div.hide{transform:translateY(4rem);opacity:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: TotopComponent, decorators: [{
type: Component,
args: [{ selector: 'sa-totop', standalone: true, imports: [CommonModule], template: `
<div
(click)="toTop()"
[style]="
'--width:' +
width +
'px;' +
'--animation-time:' +
duration +
's;' +
'--color:' +
color +
';--background:' +
background +
';--bottom:' +
bottom +
'px' +
';--end:' +
end +
'px'
"
[ngClass]="{
hide: scrollHeight < visibilityHeight && !alwaysVisible,
active: documentHieght - 1000 < scrollHeight
}"
>
<ng-container *ngIf="!customeBtn">
<button>
<svg
width="100%"
height="100%"
viewBox="-1 -1 102 102"
[style]="'--progress:' + dashOffset"
>
<path d="M50,1 a49,49 0 0,1 0,98 a49,49 0 0,1 0,-98"></path>
</svg>
<svg
id="arrow"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
>
<path
fill="currentColor"
d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"
></path>
</svg>
</button>
<div></div>
</ng-container>
<ng-content></ng-content>
</div>
`, styles: [":host{position:relative}div{position:fixed;bottom:var(--bottom);inset-inline-end:var(--end);z-index:90;transition:.5s}div button{width:var(--width);height:var(--width);border-radius:100%;overflow:hidden;aspect-ratio:1/1;position:relative;display:flex;align-items:center;justify-content:center;color:var(--color);background-color:var(--background);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);transition:var(--animation-time)}div button:after{content:\"\";position:absolute;top:50%;left:0;transform:translate(100%,-50%) rotate(-45deg);width:calc(var(--width) * 2.2);height:calc(var(--width) / 3);transition:var(--animation-time);background:linear-gradient(288deg,white,transparent)}div button svg{position:absolute;stroke:var(--color);z-index:10;fill:none;overflow:visible;transition:var(--animation-time);stroke-width:6px;stroke-dasharray:310;stroke-dashoffset:var(--progress);stroke-linecap:round}div button #arrow{width:16px}div>div{position:absolute;width:100%;height:100%;background-color:#a1a1aa;opacity:0;transition:var(--animation-time);bottom:-25px;transform:scaleY(.1);filter:blur(10px);inset-inline-end:0px}div:hover button,div.active button{transform:translateY(-4px);background-color:var(--color);color:#fff}div:hover button:after,div.active button:after{transform:translate(100%)}div:hover button svg,div.active button svg{stroke:#fff;transform:scale(.85)}div:hover div,div.active div{opacity:.5}div.hide{transform:translateY(4rem);opacity:0}\n"] }]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [PLATFORM_ID]
}] }], propDecorators: { width: [{
type: Input
}], bottom: [{
type: Input
}], end: [{
type: Input
}], color: [{
type: Input
}], scrollBehavior: [{
type: Input
}], background: [{
type: Input
}], duration: [{
type: Input
}], visibilityHeight: [{
type: Input
}], alwaysVisible: [{
type: Input
}], customeBtn: [{
type: Input
}], scrollComplete: [{
type: Output
}], toTopClicked: [{
type: Output
}] } });
/**
* Generated bundle index. Do not edit.
*/
export { TotopComponent };
//# sourceMappingURL=sa-totop.mjs.map