@gardev/components 0.0.1 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/ng-package.json +7 -0
  2. package/package.json +12 -26
  3. package/src/lib/components/bottle/bottle.component.css +4 -0
  4. package/src/lib/components/bottle/bottle.component.html +1 -0
  5. package/src/lib/components/bottle/bottle.component.spec.ts +23 -0
  6. package/src/lib/components/bottle/bottle.component.ts +164 -0
  7. package/src/lib/components/caroussel/caroussel-menu/caroussel-menu.component.css +23 -0
  8. package/src/lib/components/caroussel/caroussel-menu/caroussel-menu.component.html +5 -0
  9. package/src/lib/components/caroussel/caroussel-menu/caroussel-menu.component.ts +63 -0
  10. package/src/lib/components/caroussel/caroussel-menu/caroussel-menu.spec.ts +23 -0
  11. package/src/lib/components/caroussel/caroussel.component.css +11 -0
  12. package/src/lib/components/caroussel/caroussel.component.html +8 -0
  13. package/src/lib/components/caroussel/caroussel.component.ts +24 -0
  14. package/src/lib/components/cronogram/cronogram.component.css +58 -0
  15. package/src/lib/components/cronogram/cronogram.component.html +47 -0
  16. package/src/lib/components/cronogram/cronogram.component.spec.ts +23 -0
  17. package/src/lib/components/cronogram/cronogram.component.ts +99 -0
  18. package/src/lib/components/stack-caroussel/stack-caroussel.css +25 -0
  19. package/src/lib/components/stack-caroussel/stack-caroussel.html +4 -0
  20. package/src/lib/components/stack-caroussel/stack-caroussel.spec.ts +23 -0
  21. package/src/lib/components/stack-caroussel/stack-caroussel.ts +50 -0
  22. package/src/lib/layouts/menu/menu.component.css +50 -0
  23. package/src/lib/layouts/menu/menu.component.html +21 -0
  24. package/src/lib/layouts/menu/menu.component.ts +98 -0
  25. package/src/lib/layouts/menu/menu.spec.ts +23 -0
  26. package/src/lib/layouts/navbar/navbar.component.css +34 -0
  27. package/src/lib/layouts/navbar/navbar.component.html +10 -0
  28. package/src/lib/layouts/navbar/navbar.component.spec.ts +23 -0
  29. package/src/lib/layouts/navbar/navbar.component.ts +46 -0
  30. package/src/lib/layouts/page-layout/page-layout.component.css +13 -0
  31. package/src/lib/layouts/page-layout/page-layout.component.html +32 -0
  32. package/src/lib/layouts/page-layout/page-layout.component.spec.ts +23 -0
  33. package/src/lib/layouts/page-layout/page-layout.component.ts +13 -0
  34. package/src/lib/layouts/scroll-reactive-section/scroll-reactive-section.component.css +0 -0
  35. package/src/lib/layouts/scroll-reactive-section/scroll-reactive-section.component.html +10 -0
  36. package/src/lib/layouts/scroll-reactive-section/scroll-reactive-section.component.spec.ts +23 -0
  37. package/src/lib/layouts/scroll-reactive-section/scroll-reactive-section.component.ts +40 -0
  38. package/src/lib/layouts/section/section.component.css +0 -0
  39. package/src/lib/layouts/section/section.component.html +10 -0
  40. package/src/lib/layouts/section/section.component.spec.ts +23 -0
  41. package/src/lib/layouts/section/section.component.ts +12 -0
  42. package/src/lib/theme.service.ts +22 -0
  43. package/src/public-api.ts +14 -0
  44. package/tsconfig.lib.json +17 -0
  45. package/tsconfig.lib.prod.json +11 -0
  46. package/tsconfig.spec.json +15 -0
  47. package/fesm2022/ardev-components.mjs +0 -575
  48. package/fesm2022/ardev-components.mjs.map +0 -1
  49. package/types/ardev-components.d.ts +0 -139
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "../../dist/@ardev/components",
4
+ "lib": {
5
+ "entryFile": "src/public-api.ts"
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,26 +1,12 @@
1
- {
2
- "name": "@gardev/components",
3
- "version": "0.0.1",
4
- "publishConfig": {
5
- "access": "public"
6
- },
7
- "peerDependencies": {
8
- "@angular/common": "^21.1.0",
9
- "@angular/core": "^21.1.0"
10
- },
11
- "dependencies": {
12
- "tslib": "^2.3.0"
13
- },
14
- "sideEffects": false,
15
- "module": "fesm2022/ardev-components.mjs",
16
- "typings": "types/ardev-components.d.ts",
17
- "exports": {
18
- "./package.json": {
19
- "default": "./package.json"
20
- },
21
- ".": {
22
- "types": "./types/ardev-components.d.ts",
23
- "default": "./fesm2022/ardev-components.mjs"
24
- }
25
- }
26
- }
1
+ {
2
+ "name": "@gardev/components",
3
+ "version": "0.0.4",
4
+ "peerDependencies": {
5
+ "@angular/common": "^21.1.0",
6
+ "@angular/core": "^21.1.0"
7
+ },
8
+ "dependencies": {
9
+ "tslib": "^2.3.0"
10
+ },
11
+ "sideEffects": false
12
+ }
@@ -0,0 +1,4 @@
1
+ .three-container {
2
+ width: 300px;
3
+ height: 600px;
4
+ }
@@ -0,0 +1 @@
1
+ <div #container class="three-container"></div>
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { Bottle } from './bottle';
4
+
5
+ describe('Bottle', () => {
6
+ let component: Bottle;
7
+ let fixture: ComponentFixture<Bottle>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [Bottle]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(Bottle);
16
+ component = fixture.componentInstance;
17
+ await fixture.whenStable();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,164 @@
1
+ import { Component, ElementRef, AfterViewInit, ViewChild, Input } from '@angular/core';
2
+ import * as THREE from 'three';
3
+ import { SVGLoader } from 'three/examples/jsm/Addons.js';
4
+
5
+ @Component({
6
+ selector: 'app-bottle',
7
+ standalone: true,
8
+ templateUrl: './bottle.component.html',
9
+ styleUrls: ['./bottle.component.css'],
10
+ })
11
+ export class BottleComponent implements AfterViewInit {
12
+
13
+ @Input() color: `#${string}` = '#868132';
14
+ @Input() wineColor: `#${string}` = '#fff6f5';
15
+ @ViewChild('container', { static: true }) container!: ElementRef<HTMLDivElement>;
16
+
17
+ private scene!: THREE.Scene;
18
+ private camera!: THREE.PerspectiveCamera;
19
+ private renderer!: THREE.WebGLRenderer;
20
+
21
+ private glassMaterial!: THREE.MeshPhysicalMaterial;
22
+ private liquidMaterial!: THREE.MeshPhysicalMaterial;
23
+ private foilMaterial!: THREE.MeshPhysicalMaterial;
24
+ ngAfterViewInit() {
25
+ this.glassMaterial = new THREE.MeshPhysicalMaterial({
26
+ color: new THREE.Color(this.color),
27
+ metalness: 0,
28
+ roughness: 0,
29
+ transmission: 1,
30
+ thickness: 0,
31
+ ior: 1.5,
32
+ clearcoat: 1.0,
33
+ clearcoatRoughness: 0.05,
34
+ opacity: 1,
35
+ side: THREE.FrontSide,
36
+ transparent: true,
37
+ depthWrite: false,
38
+ envMapIntensity: 2.5
39
+ });
40
+ this.liquidMaterial = new THREE.MeshPhysicalMaterial({
41
+ color: new THREE.Color('#e2d744'),
42
+ metalness: 0.4,
43
+ // roughness: 0.25,
44
+
45
+ transmission: 0.2,
46
+ thickness: 0.4,
47
+ ior: 1.5,
48
+ clearcoat: 1.0,
49
+ clearcoatRoughness: 0.05,
50
+ transparent: true,
51
+ opacity: 0.8,
52
+
53
+ depthWrite: false, // 🔑 el líquid SÍ escriu profunditat
54
+ side: THREE.BackSide,
55
+ // envMapIntensity: 1.2,
56
+ });
57
+
58
+
59
+ this.foilMaterial = new THREE.MeshPhysicalMaterial({
60
+ color: 0x156289,
61
+ metalness: 0.25,
62
+ roughness: 0.3,
63
+ side: THREE.DoubleSide
64
+ });
65
+ this.createSceneAndLighting();
66
+ this.loadModelFromSVGFile();
67
+ this.animate();
68
+ }
69
+
70
+ private animate = () => {
71
+ requestAnimationFrame(this.animate);
72
+
73
+ if (this.camera) {
74
+ const t = Date.now() * 0.0002;
75
+ this.camera.position.x = Math.sin(t) * 50;
76
+ this.camera.position.z = Math.cos(t) * 50;
77
+ this.camera.lookAt(0, 0, 0);
78
+ }
79
+ this.renderer.shadowMap.enabled = true;
80
+ this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
81
+
82
+ this.renderer.render(this.scene, this.camera);
83
+ };
84
+
85
+ private loadModelFromSVGFile() {
86
+ const loader = new SVGLoader();
87
+
88
+ loader.load('assets/bitmap.svg', (data) => {
89
+ const bottleGroup = new THREE.Group();
90
+
91
+ data.paths.forEach((path, index) => {
92
+ const shapes = SVGLoader.createShapes(path);
93
+
94
+ shapes.forEach((shape) => {
95
+ const points = shape.getPoints().map(p => new THREE.Vector2(p.x * 0.1, -p.y * 0.1));
96
+
97
+ const geometry = new THREE.LatheGeometry(points, 128); // més segments → més suau
98
+ geometry.computeVertexNormals(); // normals correctes
99
+
100
+ const material = (index === 0) ? this.glassMaterial :
101
+ (index === 1) ? this.liquidMaterial : this.foilMaterial
102
+
103
+
104
+ const mesh = new THREE.Mesh(geometry, material);
105
+
106
+ const layerGroup = new THREE.Group();
107
+ layerGroup.add(mesh);
108
+ bottleGroup.add(layerGroup);
109
+ });
110
+ });
111
+
112
+ const box = new THREE.Box3().setFromObject(bottleGroup);
113
+ const center = box.getCenter(new THREE.Vector3());
114
+ bottleGroup.position.sub(center);
115
+
116
+ this.scene.add(bottleGroup);
117
+ });
118
+ }
119
+
120
+ private createSceneAndLighting() {
121
+ this.scene = new THREE.Scene();
122
+
123
+ const width = this.container.nativeElement.clientWidth;
124
+ const height = this.container.nativeElement.clientHeight;
125
+
126
+ this.camera = new THREE.PerspectiveCamera(35, width / height, 0.1, 5000);
127
+ this.camera.position.set(30, 20, 50);
128
+ this.camera.lookAt(0, 0, 0);
129
+
130
+ this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
131
+ this.renderer.setSize(width, height);
132
+ this.renderer.toneMapping = THREE.ACESFilmicToneMapping; // millora realisme colors
133
+ this.container.nativeElement.appendChild(this.renderer.domElement);
134
+
135
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
136
+ this.scene.add(ambientLight);
137
+
138
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
139
+ directionalLight.position.set(50, 80, 50);
140
+ directionalLight.castShadow = true;
141
+ directionalLight.shadow.mapSize.width = 2048;
142
+ directionalLight.shadow.mapSize.height = 2048;
143
+ directionalLight.shadow.radius = 4;
144
+ this.scene.add(directionalLight);
145
+
146
+ const backLight = new THREE.PointLight(0xffffff, 0.5);
147
+ backLight.position.set(-30, 40, -30);
148
+ this.scene.add(backLight);
149
+
150
+ const sideLight = new THREE.PointLight(0xffffff, 0.3);
151
+ sideLight.position.set(30, 10, -40);
152
+ this.scene.add(sideLight);
153
+
154
+ const textureLoader = new THREE.TextureLoader();
155
+ textureLoader.load('assets/environment-map.png', (texture) => {
156
+ texture.mapping = THREE.EquirectangularReflectionMapping;
157
+ this.scene.environment = texture;
158
+ //this.scene.background = texture;
159
+ });
160
+
161
+
162
+ }
163
+
164
+ }
@@ -0,0 +1,23 @@
1
+ button {
2
+ width: calc(1rem - 4px);
3
+ height: calc(1rem - 4px);
4
+ background: black;
5
+ border: 0;
6
+ border-radius: 1rem;
7
+ z-index: 1;
8
+ margin: 2px;
9
+ cursor: pointer
10
+ }
11
+
12
+ #selectedIndex {
13
+ width: 1rem;
14
+ height: 1rem;
15
+ background: rgb(255, 255, 255);
16
+ border-radius: 1rem;
17
+ position: absolute;
18
+ z-index: 0;
19
+ transition:
20
+ transform 300ms cubic-bezier(0.35, 0, 0.25, 1),
21
+ width 300ms cubic-bezier(0.35, 0, 0.25, 1);
22
+ will-change: transform, width;
23
+ }
@@ -0,0 +1,5 @@
1
+ <div style="display: flex; gap: 1rem;">
2
+ <button #btn *ngFor="let _ of [].constructor(length); let i = index" (click)="selectIndex(i)">
3
+ </button>
4
+ <div #selectedIndex id="selectedIndex"></div>
5
+ </div>
@@ -0,0 +1,63 @@
1
+ import {
2
+ Component,
3
+ ElementRef,
4
+ QueryList,
5
+ ViewChild,
6
+ ViewChildren,
7
+ Output,
8
+ EventEmitter,
9
+ Input,
10
+ AfterViewInit
11
+ } from '@angular/core';
12
+ import { NgForOf } from '@angular/common';
13
+
14
+ @Component({
15
+ selector: 'ard-caroussel-menu',
16
+ standalone: true,
17
+ imports: [NgForOf],
18
+ templateUrl: './caroussel-menu.component.html',
19
+ styleUrls: ['./caroussel-menu.component.css'],
20
+ })
21
+ export class CarousselMenuComponent implements AfterViewInit {
22
+ @Input() length = 0;
23
+
24
+ @ViewChildren('btn', { read: ElementRef })
25
+ buttons!: QueryList<ElementRef<HTMLButtonElement>>;
26
+
27
+ @ViewChild('selectedIndex')
28
+ selectedIndex!: ElementRef<HTMLElement>;
29
+
30
+ @Output() indexChange = new EventEmitter<number>();
31
+
32
+ private positions: number[] = [];
33
+ private resetWidthId?: number;
34
+
35
+ ngAfterViewInit() {
36
+ const btns = this.buttons.toArray();
37
+ const firstRight = btns[0]?.nativeElement.getBoundingClientRect().right ?? 0;
38
+
39
+ this.positions = btns.map(
40
+ b => b.nativeElement.getBoundingClientRect().right - firstRight
41
+ );
42
+ }
43
+
44
+ selectIndex(i: number) {
45
+ this.indexChange.emit(i);
46
+
47
+ const el = this.selectedIndex.nativeElement;
48
+ const x = this.positions[i] ?? 0;
49
+
50
+ el.style.transform = `translateX(${x}px)`;
51
+
52
+ const baseWidth = el.getBoundingClientRect().width;
53
+ el.style.width = `${baseWidth * 1.5}px`;
54
+
55
+ if (this.resetWidthId) {
56
+ clearTimeout(this.resetWidthId);
57
+ }
58
+
59
+ this.resetWidthId = window.setTimeout(() => {
60
+ el.style.width = `${baseWidth}px`;
61
+ }, 150);
62
+ }
63
+ }
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { CarousselMenuComponent } from './caroussel-menu.component';
4
+
5
+ describe('CarousselMenuComponent', () => {
6
+ let component: CarousselMenuComponent;
7
+ let fixture: ComponentFixture<CarousselMenuComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [CarousselMenuComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(CarousselMenuComponent);
16
+ component = fixture.componentInstance;
17
+ await fixture.whenStable();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,11 @@
1
+ .image {
2
+ position: absolute;
3
+ top: 0;
4
+ left: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ object-fit: cover;
8
+ object-position: center;
9
+ transition: opacity 0.5s ease-in-out;
10
+ /* <-- transició suau */
11
+ }
@@ -0,0 +1,8 @@
1
+ <div style="position: relative; top: 0; width: 100%; height: 100%; overflow: hidden;">
2
+ <img *ngFor="let img of images; let i = index" [src]="img" [style.opacity]="i === index ? 1 : 0" class="image"
3
+ alt="">
4
+
5
+ <div style="position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); display: flex; gap: 8px;">
6
+ <ard-caroussel-menu (indexChange)="goTo($event)" [length]="images.length"></ard-caroussel-menu>
7
+ </div>
8
+ </div>
@@ -0,0 +1,24 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { NgForOf } from "@angular/common";
3
+ import { CarousselMenuComponent } from './caroussel-menu/caroussel-menu.component';
4
+
5
+ @Component({
6
+ selector: 'ard-caroussel',
7
+ imports: [NgForOf, CarousselMenuComponent],
8
+ templateUrl: './caroussel.component.html',
9
+ styleUrl: './caroussel.component.css',
10
+ })
11
+ export class CarousselComponent {
12
+ @Input() images: string[] = [];
13
+
14
+ index = 0;
15
+
16
+ next() {
17
+ this.index = (this.index + 1) % this.images.length;
18
+ }
19
+
20
+ goTo(i: number) {
21
+ this.index = i;
22
+ }
23
+
24
+ }
@@ -0,0 +1,58 @@
1
+ .left-container.odd {
2
+ padding: 0 1rem
3
+ }
4
+
5
+ .right-container.even {
6
+ padding: 0 1rem;
7
+ }
8
+
9
+ .left-container,
10
+ .right-container {
11
+ padding: 0 1rem;
12
+ max-width: 35ch;
13
+ }
14
+
15
+ .general-container {
16
+ transition: opacity 0.6s;
17
+
18
+ }
19
+
20
+ .line {
21
+ background: var(--color-text);
22
+ width: 100%;
23
+ position: absolute;
24
+ border-radius: 1rem 1rem 0 0;
25
+ animation-timing-function: ease-out;
26
+ width: 0.4rem
27
+ }
28
+
29
+ .bullet {
30
+ width: 0.4rem;
31
+ min-height: 0.4rem;
32
+ background: var(--color-text);
33
+ outline: 3px solid var(--color-text);
34
+ border-radius: 2rem;
35
+ position: absolute;
36
+ }
37
+
38
+ .hidden {
39
+ opacity: 0;
40
+ }
41
+
42
+ .visible {
43
+ opacity: 1;
44
+ }
45
+
46
+ .center {
47
+ position: relative;
48
+ }
49
+
50
+
51
+
52
+ .left-container {
53
+ display: flex;
54
+ justify-content: end;
55
+ text-align: end;
56
+ justify-self: end;
57
+ flex-flow: column
58
+ }
@@ -0,0 +1,47 @@
1
+ <h4>cronogram.component.ts</h4>
2
+
3
+ <p>
4
+ en la vista mobile, estarà tot en un mateix costat?
5
+ </p>
6
+
7
+ <div #wrapper>
8
+
9
+
10
+
11
+ @for(day of items; track day.date; let i = $index;) {
12
+
13
+ <div style="display: grid; grid-template-columns: 1fr 0fr 1fr;" class="general-container" #CronogramContent>
14
+
15
+
16
+ <div class="left-container" [ngClass]="i % 2 == 0 ? 'odd' : 'even'">
17
+ @if(i % 2 === 0) {
18
+ <h3>{{day.date}}</h3>
19
+ <p>lorem ipsum dolor sit amet, lorem ipsum dolor sit amet, lorem ipsum dolor sit amet, lorem ipsum dolor sit
20
+ amet, lorem ipsum dolor sit amet, lorem ipsum dolor sit amet,</p>
21
+ }
22
+ </div>
23
+
24
+
25
+ <div class="center" style="height: 100%; display: flex; width: 1rem; flex-flow: column; position: relative">
26
+ <div class="bullet" style="z-index: 2">
27
+ </div>
28
+
29
+ @if (i == 0) {
30
+ <div class="line" #line>
31
+
32
+ </div>
33
+ }
34
+
35
+ </div>
36
+ <div class="right-container cronogram-content" [ngClass]="i % 2 == 0 ? 'odd' : 'even'">
37
+ @if(i % 2 !== 0) {
38
+ <h3>{{day.date}}</h3>
39
+ <p>lorem ipsum dolor sit amet, lorem ipsum dolor sit amet, lorem ipsum dolor sit amet, lorem ipsum dolor sit
40
+ amet, lorem ipsum dolor sit amet, lorem ipsum dolor sit amet,</p>
41
+
42
+ }
43
+ </div>
44
+
45
+ </div>
46
+ }
47
+ </div>
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { CronogramComponent } from './cronogram.component';
4
+
5
+ describe('CronogramComponent', () => {
6
+ let component: CronogramComponent;
7
+ let fixture: ComponentFixture<CronogramComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [CronogramComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(CronogramComponent);
16
+ component = fixture.componentInstance;
17
+ await fixture.whenStable();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,99 @@
1
+ import { Component, ElementRef, HostListener, QueryList, ViewChild, ViewChildren } from '@angular/core';
2
+ import { NgClass } from "@angular/common";
3
+
4
+ @Component({
5
+ selector: 'ard-cronogram',
6
+ imports: [NgClass],
7
+ templateUrl: './cronogram.component.html',
8
+ styleUrl: './cronogram.component.css',
9
+ })
10
+ export class CronogramComponent {
11
+ @ViewChild('wrapper', { read: ElementRef }) wrapper!: ElementRef<HTMLElement>;
12
+ @ViewChild('line', { read: ElementRef }) line!: ElementRef<HTMLElement>;
13
+
14
+ @ViewChildren('CronogramContent', { read: ElementRef })
15
+ children!: QueryList<ElementRef>;
16
+ items = [
17
+ { date: 2000, content: 'Lorem ipsum dolor sit amet', image: 'lorem' },
18
+ { date: 2001, content: 'Lorem ipsum dolor sit amet', image: 'lorem' },
19
+ { date: 2002, content: 'Lorem ipsum dolor sit amet', image: 'lorem' }
20
+ ]
21
+
22
+ positionsY: number[] = []
23
+
24
+ ngAfterViewInit() {
25
+ this.positionsY = this.children.map(i => i.nativeElement.getBoundingClientRect().y)
26
+
27
+ this.line.nativeElement.style.maxHeight = `${this.wrapper.nativeElement.getBoundingClientRect().height}px`
28
+ }
29
+
30
+ lastScrollY = window.scrollY;
31
+
32
+ @HostListener('window:scroll', [])
33
+ onScroll() {
34
+ const scrollPosition = window.scrollY;
35
+
36
+ if (scrollPosition > this.lastScrollY) {
37
+ this.onScrollDown(scrollPosition);
38
+ } else if (scrollPosition < this.lastScrollY) {
39
+ this.onScrollUp(scrollPosition);
40
+ }
41
+
42
+ this.lastScrollY = scrollPosition;
43
+
44
+ this.line.nativeElement.style.height = `${this.visibleHeight(this.wrapper.nativeElement)}px`
45
+
46
+
47
+ }
48
+ onScrollDown(scrollPosition: number) {
49
+ let index = this.positionsY.findIndex(pos => pos > scrollPosition - 100);
50
+
51
+ if (index === -1) {
52
+ index = this.positionsY.length;
53
+ }
54
+
55
+ this.children.forEach((child, i) => {
56
+ const el = child.nativeElement as HTMLElement;
57
+
58
+ if (i < index) {
59
+ el.classList.remove("hidden");
60
+ el.classList.add("visible");
61
+ }
62
+ });
63
+
64
+ this.line.nativeElement.style.transition = 'height 1.2s';
65
+
66
+ }
67
+ onScrollUp(scrollPosition: number) {
68
+ let index = this.positionsY.findIndex(pos => pos > scrollPosition - 50);
69
+
70
+ if (index === -1) {
71
+ index = this.positionsY.length;
72
+ }
73
+
74
+ this.children.forEach((child, i) => {
75
+ const el = child.nativeElement as HTMLElement;
76
+
77
+ if (i >= index) {
78
+ el.classList.add("hidden");
79
+ el.classList.remove("visible");
80
+ }
81
+ });
82
+
83
+ this.line.nativeElement.style.transition = 'height 0s';
84
+
85
+ }
86
+
87
+
88
+
89
+ visibleHeight(el: HTMLElement) {
90
+ const rect = el.getBoundingClientRect();
91
+ const viewportHeight = window.innerHeight;
92
+
93
+ const topVisible = Math.max(rect.top, 0);
94
+ const bottomVisible = Math.min(rect.bottom, viewportHeight);
95
+
96
+ return Math.max(0, bottomVisible - topVisible);
97
+ }
98
+
99
+ }
@@ -0,0 +1,25 @@
1
+ :host {
2
+ --anim-speed: 300ms;
3
+ /* VARIABLE DE VELOCITAT */
4
+ }
5
+
6
+ .stack-container {
7
+ position: relative;
8
+ width: 400px;
9
+ height: 400px;
10
+ cursor: pointer;
11
+ }
12
+
13
+ .stack-image {
14
+ position: absolute;
15
+ width: 200px;
16
+ height: 200px;
17
+ object-fit: cover;
18
+ transition:
19
+ transform var(--anim-speed) ease,
20
+ opacity var(--anim-speed) ease;
21
+ }
22
+
23
+ .stack-image.move-out {
24
+ transform: translate(200px, 0px) !important;
25
+ }
@@ -0,0 +1,4 @@
1
+ <div class="stack-container" (click)="rotateStack()">
2
+ <img *ngFor="let img of images; let i = index; let last = last" [src]="img" [ngStyle]="getOffset(i)"
3
+ [class.img-last]="last" class="stack-image" />
4
+ </div>