feat: add @sda/flair-elements-ui library
Angular 19+ standalone library with 61 components, 15 directives, and 8 services for decorative visual effects, animations, and micro-interactions. Components include particle systems, flow fields, aurora effects, tilt/holographic/spotlight cards, text effects, dividers, scroll animations, generative art, celebrations, image treatments, morphing shapes, terminal output, and pattern textures. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
30
src/components/fl-card-stack/fl-card-stack.component.scss
Normal file
30
src/components/fl-card-stack/fl-card-stack.component.scss
Normal file
@@ -0,0 +1,30 @@
|
||||
:host {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fl-card-stack__container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
> * {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
:host.fl-card-stack--hover-expand {
|
||||
.fl-card-stack__container > *:hover {
|
||||
transform: translate(-50%, -50%) rotate(0deg) scale(1.05) !important;
|
||||
z-index: 1000 !important;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
:host.fl-card-stack--reduced-motion {
|
||||
.fl-card-stack__container > * {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
62
src/components/fl-card-stack/fl-card-stack.component.ts
Normal file
62
src/components/fl-card-stack/fl-card-stack.component.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import {
|
||||
Component, ChangeDetectionStrategy, input, inject,
|
||||
DestroyRef, ElementRef, afterNextRender,
|
||||
} from '@angular/core';
|
||||
import { ReducedMotionService } from '../../services/reduced-motion.service';
|
||||
|
||||
@Component({
|
||||
selector: 'fl-card-stack',
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `
|
||||
<div class="fl-card-stack__container">
|
||||
<ng-content />
|
||||
</div>
|
||||
`,
|
||||
styleUrl: './fl-card-stack.component.scss',
|
||||
host: {
|
||||
'class': 'fl-card-stack',
|
||||
'[class.fl-card-stack--reduced-motion]': 'reducedMotion.reduced()',
|
||||
'[class.fl-card-stack--hover-expand]': 'hoverExpand()',
|
||||
},
|
||||
})
|
||||
export class FlCardStackComponent {
|
||||
protected reducedMotion = inject(ReducedMotionService);
|
||||
private destroyRef = inject(DestroyRef);
|
||||
private el = inject(ElementRef);
|
||||
|
||||
// Inputs
|
||||
readonly spread = input(20);
|
||||
readonly rotation = input(3);
|
||||
readonly hoverExpand = input(true);
|
||||
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.applyCardStyles();
|
||||
});
|
||||
}
|
||||
|
||||
private applyCardStyles(): void {
|
||||
const container = this.el.nativeElement.querySelector('.fl-card-stack__container') as HTMLElement;
|
||||
if (!container) return;
|
||||
|
||||
const children = Array.from(container.children) as HTMLElement[];
|
||||
const total = children.length;
|
||||
const spreadPx = this.spread();
|
||||
const rotationDeg = this.rotation();
|
||||
|
||||
children.forEach((child, index) => {
|
||||
const offset = (index - (total - 1) / 2);
|
||||
const translateY = offset * spreadPx;
|
||||
const rotate = offset * rotationDeg;
|
||||
const zIndex = total - Math.abs(index - Math.floor(total / 2));
|
||||
|
||||
child.style.position = 'absolute';
|
||||
child.style.top = '50%';
|
||||
child.style.left = '50%';
|
||||
child.style.transform = `translate(-50%, calc(-50% + ${translateY}px)) rotate(${rotate}deg)`;
|
||||
child.style.zIndex = `${zIndex}`;
|
||||
child.style.transition = 'transform 0.3s ease';
|
||||
});
|
||||
}
|
||||
}
|
||||
1
src/components/fl-card-stack/index.ts
Normal file
1
src/components/fl-card-stack/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './fl-card-stack.component';
|
||||
Reference in New Issue
Block a user