Add comprehensive library expansion with new components and demos
- Add new libraries: ui-accessibility, ui-animations, ui-backgrounds, ui-code-display, ui-data-utils, ui-font-manager, hcl-studio - Add extensive layout components: gallery-grid, infinite-scroll-container, kanban-board, masonry, split-view, sticky-layout - Add comprehensive demo components for all new features - Update project configuration and dependencies - Expand component exports and routing structure - Add UI landing pages planning document 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
63
projects/ui-backgrounds/README.md
Normal file
63
projects/ui-backgrounds/README.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# UiBackgrounds
|
||||
|
||||
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||
|
||||
```bash
|
||||
ng generate component component-name
|
||||
```
|
||||
|
||||
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||
|
||||
```bash
|
||||
ng generate --help
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To build the library, run:
|
||||
|
||||
```bash
|
||||
ng build ui-backgrounds
|
||||
```
|
||||
|
||||
This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
|
||||
|
||||
### Publishing the Library
|
||||
|
||||
Once the project is built, you can publish your library by following these steps:
|
||||
|
||||
1. Navigate to the `dist` directory:
|
||||
```bash
|
||||
cd dist/ui-backgrounds
|
||||
```
|
||||
|
||||
2. Run the `npm publish` command to publish your library to the npm registry:
|
||||
```bash
|
||||
npm publish
|
||||
```
|
||||
|
||||
## Running unit tests
|
||||
|
||||
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
||||
|
||||
```bash
|
||||
ng test
|
||||
```
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
For end-to-end (e2e) testing, run:
|
||||
|
||||
```bash
|
||||
ng e2e
|
||||
```
|
||||
|
||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||
|
||||
## Additional Resources
|
||||
|
||||
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||
7
projects/ui-backgrounds/ng-package.json
Normal file
7
projects/ui-backgrounds/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../dist/ui-backgrounds",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
12
projects/ui-backgrounds/package.json
Normal file
12
projects/ui-backgrounds/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "ui-backgrounds",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^19.2.0",
|
||||
"@angular/core": "^19.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"sideEffects": false
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges, ElementRef, inject, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
|
||||
import { LinearGradientConfig, RadialGradientConfig, ConicGradientConfig, ColorStop, GradientDirection } from '../../types/background.types';
|
||||
import { BackgroundService } from '../../services/background.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-gradient-background',
|
||||
standalone: true,
|
||||
template: '<ng-content></ng-content>',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: {
|
||||
'class': 'ui-background ui-background--gradient'
|
||||
}
|
||||
})
|
||||
export class GradientBackgroundComponent implements OnInit, OnDestroy, OnChanges {
|
||||
private readonly elementRef = inject(ElementRef<HTMLElement>);
|
||||
private readonly backgroundService = inject(BackgroundService);
|
||||
private backgroundId?: string;
|
||||
|
||||
@Input() type: 'linear' | 'radial' | 'conic' = 'linear';
|
||||
@Input() colors: string[] = ['#000000', '#ffffff'];
|
||||
@Input() direction?: GradientDirection | string;
|
||||
@Input() shape?: 'circle' | 'ellipse';
|
||||
@Input() size?: 'closest-side' | 'closest-corner' | 'farthest-side' | 'farthest-corner';
|
||||
@Input() position?: string;
|
||||
@Input() angle?: string | number;
|
||||
@Input() colorStops?: ColorStop[];
|
||||
@Input() fullScreen = false;
|
||||
@Input() zIndex?: number;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.applyBackground();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
const relevantChanges = ['type', 'colors', 'direction', 'shape', 'size', 'position', 'angle', 'colorStops', 'fullScreen', 'zIndex'];
|
||||
if (relevantChanges.some(key => changes[key])) {
|
||||
this.applyBackground();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.backgroundId) {
|
||||
this.backgroundService.removeBackground(this.backgroundId);
|
||||
}
|
||||
}
|
||||
|
||||
private applyBackground(): void {
|
||||
if (this.backgroundId) {
|
||||
this.backgroundService.removeBackground(this.backgroundId);
|
||||
}
|
||||
|
||||
const colorStops = this.colorStops || this.colors.map(color => ({ color }));
|
||||
let config: LinearGradientConfig | RadialGradientConfig | ConicGradientConfig;
|
||||
|
||||
switch (this.type) {
|
||||
case 'linear':
|
||||
config = {
|
||||
type: 'linear-gradient',
|
||||
direction: this.direction,
|
||||
colors: colorStops
|
||||
};
|
||||
break;
|
||||
case 'radial':
|
||||
config = {
|
||||
type: 'radial-gradient',
|
||||
shape: this.shape,
|
||||
size: this.size,
|
||||
position: this.position,
|
||||
colors: colorStops
|
||||
};
|
||||
break;
|
||||
case 'conic':
|
||||
config = {
|
||||
type: 'conic-gradient',
|
||||
angle: this.angle,
|
||||
position: this.position,
|
||||
colors: colorStops
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.fullScreen) {
|
||||
this.backgroundId = this.backgroundService.applyFullScreenBackground(config, {
|
||||
zIndex: this.zIndex || -1
|
||||
});
|
||||
} else {
|
||||
this.backgroundId = this.backgroundService.applyBackground(
|
||||
this.elementRef.nativeElement,
|
||||
config
|
||||
);
|
||||
}
|
||||
|
||||
// Update host class
|
||||
this.elementRef.nativeElement.classList.add(`ui-background--${this.type}-gradient`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges, ElementRef, inject, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
|
||||
import { ImageBackgroundConfig } from '../../types/background.types';
|
||||
import { BackgroundService } from '../../services/background.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-image-background',
|
||||
standalone: true,
|
||||
template: '<ng-content></ng-content>',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: {
|
||||
'class': 'ui-background ui-background--image'
|
||||
}
|
||||
})
|
||||
export class ImageBackgroundComponent implements OnInit, OnDestroy, OnChanges {
|
||||
private readonly elementRef = inject(ElementRef<HTMLElement>);
|
||||
private readonly backgroundService = inject(BackgroundService);
|
||||
private backgroundId?: string;
|
||||
|
||||
@Input({ required: true }) url!: string;
|
||||
@Input() size: 'auto' | 'cover' | 'contain' | string = 'cover';
|
||||
@Input() position = 'center';
|
||||
@Input() repeat: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat' = 'no-repeat';
|
||||
@Input() attachment?: 'scroll' | 'fixed' | 'local';
|
||||
@Input() opacity = 1;
|
||||
@Input() fullScreen = false;
|
||||
@Input() zIndex?: number;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.applyBackground();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
const relevantChanges = ['url', 'size', 'position', 'repeat', 'attachment', 'opacity', 'fullScreen', 'zIndex'];
|
||||
if (relevantChanges.some(key => changes[key])) {
|
||||
this.applyBackground();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.backgroundId) {
|
||||
this.backgroundService.removeBackground(this.backgroundId);
|
||||
}
|
||||
}
|
||||
|
||||
private applyBackground(): void {
|
||||
if (!this.url) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.backgroundId) {
|
||||
this.backgroundService.removeBackground(this.backgroundId);
|
||||
}
|
||||
|
||||
const config: ImageBackgroundConfig = {
|
||||
type: 'image',
|
||||
url: this.url,
|
||||
size: this.size,
|
||||
position: this.position,
|
||||
repeat: this.repeat,
|
||||
attachment: this.attachment,
|
||||
opacity: this.opacity
|
||||
};
|
||||
|
||||
if (this.fullScreen) {
|
||||
this.backgroundId = this.backgroundService.applyFullScreenBackground(config, {
|
||||
zIndex: this.zIndex || -1
|
||||
});
|
||||
} else {
|
||||
this.backgroundId = this.backgroundService.applyBackground(
|
||||
this.elementRef.nativeElement,
|
||||
config
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './solid-background.component';
|
||||
export * from './gradient-background.component';
|
||||
export * from './pattern-background.component';
|
||||
export * from './image-background.component';
|
||||
@@ -0,0 +1,73 @@
|
||||
import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges, ElementRef, inject, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
|
||||
import { PatternConfig, PatternType } from '../../types/background.types';
|
||||
import { BackgroundService } from '../../services/background.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-pattern-background',
|
||||
standalone: true,
|
||||
template: '<ng-content></ng-content>',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: {
|
||||
'class': 'ui-background ui-background--pattern'
|
||||
}
|
||||
})
|
||||
export class PatternBackgroundComponent implements OnInit, OnDestroy, OnChanges {
|
||||
private readonly elementRef = inject(ElementRef<HTMLElement>);
|
||||
private readonly backgroundService = inject(BackgroundService);
|
||||
private backgroundId?: string;
|
||||
|
||||
@Input() pattern: PatternType = 'dots';
|
||||
@Input() primaryColor = '#000000';
|
||||
@Input() secondaryColor = '#ffffff';
|
||||
@Input() size: string | number = 20;
|
||||
@Input() opacity = 1;
|
||||
@Input() fullScreen = false;
|
||||
@Input() zIndex?: number;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.applyBackground();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
const relevantChanges = ['pattern', 'primaryColor', 'secondaryColor', 'size', 'opacity', 'fullScreen', 'zIndex'];
|
||||
if (relevantChanges.some(key => changes[key])) {
|
||||
this.applyBackground();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.backgroundId) {
|
||||
this.backgroundService.removeBackground(this.backgroundId);
|
||||
}
|
||||
}
|
||||
|
||||
private applyBackground(): void {
|
||||
if (this.backgroundId) {
|
||||
this.backgroundService.removeBackground(this.backgroundId);
|
||||
}
|
||||
|
||||
const config: PatternConfig = {
|
||||
type: 'pattern',
|
||||
pattern: this.pattern,
|
||||
primaryColor: this.primaryColor,
|
||||
secondaryColor: this.secondaryColor,
|
||||
size: this.size,
|
||||
opacity: this.opacity
|
||||
};
|
||||
|
||||
if (this.fullScreen) {
|
||||
this.backgroundId = this.backgroundService.applyFullScreenBackground(config, {
|
||||
zIndex: this.zIndex || -1
|
||||
});
|
||||
} else {
|
||||
this.backgroundId = this.backgroundService.applyBackground(
|
||||
this.elementRef.nativeElement,
|
||||
config
|
||||
);
|
||||
}
|
||||
|
||||
// Update host class
|
||||
this.elementRef.nativeElement.classList.add(`ui-background--pattern-${this.pattern}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges, ElementRef, inject, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
|
||||
import { SolidBackgroundConfig } from '../../types/background.types';
|
||||
import { BackgroundService } from '../../services/background.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-solid-background',
|
||||
standalone: true,
|
||||
template: '<ng-content></ng-content>',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: {
|
||||
'class': 'ui-background ui-background--solid'
|
||||
}
|
||||
})
|
||||
export class SolidBackgroundComponent implements OnInit, OnDestroy, OnChanges {
|
||||
private readonly elementRef = inject(ElementRef<HTMLElement>);
|
||||
private readonly backgroundService = inject(BackgroundService);
|
||||
private backgroundId?: string;
|
||||
|
||||
@Input() color = '#000000';
|
||||
@Input() fullScreen = false;
|
||||
@Input() zIndex?: number;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.applyBackground();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes['color'] || changes['fullScreen'] || changes['zIndex']) {
|
||||
this.applyBackground();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.backgroundId) {
|
||||
this.backgroundService.removeBackground(this.backgroundId);
|
||||
}
|
||||
}
|
||||
|
||||
private applyBackground(): void {
|
||||
if (this.backgroundId) {
|
||||
this.backgroundService.removeBackground(this.backgroundId);
|
||||
}
|
||||
|
||||
const config: SolidBackgroundConfig = {
|
||||
type: 'solid',
|
||||
color: this.color
|
||||
};
|
||||
|
||||
if (this.fullScreen) {
|
||||
this.backgroundId = this.backgroundService.applyFullScreenBackground(config, {
|
||||
zIndex: this.zIndex || -1
|
||||
});
|
||||
} else {
|
||||
this.backgroundId = this.backgroundService.applyBackground(
|
||||
this.elementRef.nativeElement,
|
||||
config
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
projects/ui-backgrounds/src/lib/components/index.ts
Normal file
1
projects/ui-backgrounds/src/lib/components/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './backgrounds/index';
|
||||
@@ -0,0 +1,122 @@
|
||||
import {
|
||||
Directive,
|
||||
Input,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
OnChanges,
|
||||
SimpleChanges,
|
||||
ElementRef,
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import { BackgroundConfig, BackgroundOptions } from '../types/background.types';
|
||||
import { BackgroundService } from '../services/background.service';
|
||||
|
||||
@Directive({
|
||||
selector: '[uiBackground]',
|
||||
standalone: true
|
||||
})
|
||||
export class BackgroundDirective implements OnInit, OnDestroy, OnChanges {
|
||||
private readonly elementRef = inject(ElementRef<HTMLElement>);
|
||||
private readonly backgroundService = inject(BackgroundService);
|
||||
private backgroundId?: string;
|
||||
|
||||
@Input('uiBackground') config?: BackgroundConfig;
|
||||
@Input() backgroundOptions?: Partial<BackgroundOptions>;
|
||||
@Input() backgroundDisabled = false;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.applyBackground();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes['config'] || changes['backgroundOptions'] || changes['backgroundDisabled']) {
|
||||
if (this.backgroundDisabled) {
|
||||
this.removeBackground();
|
||||
} else {
|
||||
this.applyBackground();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.removeBackground();
|
||||
}
|
||||
|
||||
private applyBackground(): void {
|
||||
if (!this.config || this.backgroundDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove existing background if present
|
||||
this.removeBackground();
|
||||
|
||||
// Apply new background
|
||||
this.backgroundId = this.backgroundService.applyBackground(
|
||||
this.elementRef.nativeElement,
|
||||
this.config
|
||||
);
|
||||
|
||||
// Add base CSS class for styling
|
||||
this.elementRef.nativeElement.classList.add('ui-background');
|
||||
|
||||
// Add specific CSS classes based on configuration
|
||||
this.addTypeClasses();
|
||||
}
|
||||
|
||||
private removeBackground(): void {
|
||||
if (this.backgroundId) {
|
||||
this.backgroundService.removeBackground(this.backgroundId);
|
||||
this.backgroundId = undefined;
|
||||
}
|
||||
|
||||
// Remove CSS classes
|
||||
this.removeTypeClasses();
|
||||
this.elementRef.nativeElement.classList.remove('ui-background');
|
||||
}
|
||||
|
||||
private addTypeClasses(): void {
|
||||
if (!this.config) return;
|
||||
|
||||
const element = this.elementRef.nativeElement;
|
||||
element.classList.add(`ui-background--${this.config.type}`);
|
||||
|
||||
// Add additional classes based on type
|
||||
switch (this.config.type) {
|
||||
case 'linear-gradient':
|
||||
case 'radial-gradient':
|
||||
case 'conic-gradient':
|
||||
element.classList.add('ui-background--gradient');
|
||||
break;
|
||||
case 'pattern':
|
||||
element.classList.add('ui-background--pattern');
|
||||
if (this.config.pattern) {
|
||||
element.classList.add(`ui-background--pattern-${this.config.pattern}`);
|
||||
}
|
||||
break;
|
||||
case 'image':
|
||||
element.classList.add('ui-background--image');
|
||||
break;
|
||||
case 'animated':
|
||||
element.classList.add('ui-background--animated');
|
||||
break;
|
||||
case 'glass':
|
||||
element.classList.add('ui-background--glass');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private removeTypeClasses(): void {
|
||||
if (!this.config) return;
|
||||
|
||||
const element = this.elementRef.nativeElement;
|
||||
const classesToRemove: string[] = [];
|
||||
|
||||
element.classList.forEach((cls: string) => {
|
||||
if (cls.startsWith('ui-background--')) {
|
||||
classesToRemove.push(cls);
|
||||
}
|
||||
});
|
||||
|
||||
classesToRemove.forEach(cls => element.classList.remove(cls));
|
||||
}
|
||||
}
|
||||
1
projects/ui-backgrounds/src/lib/directives/index.ts
Normal file
1
projects/ui-backgrounds/src/lib/directives/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './background.directive';
|
||||
191
projects/ui-backgrounds/src/lib/services/background.service.ts
Normal file
191
projects/ui-backgrounds/src/lib/services/background.service.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
import { Injectable, signal, computed } from '@angular/core';
|
||||
import { BackgroundConfig, BackgroundOptions, BackgroundState } from '../types/background.types';
|
||||
import { BackgroundGenerator } from '../utils/background-generator';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class BackgroundService {
|
||||
private _activeBackgrounds = signal<Map<string, BackgroundState>>(new Map());
|
||||
|
||||
// Public computed signals
|
||||
readonly activeBackgrounds = computed(() => Array.from(this._activeBackgrounds().values()));
|
||||
readonly hasActiveBackgrounds = computed(() => this._activeBackgrounds().size > 0);
|
||||
|
||||
/**
|
||||
* Apply a background to an element
|
||||
*/
|
||||
applyBackground(element: HTMLElement, config: BackgroundConfig, id?: string): string {
|
||||
const backgroundId = id || this.generateId();
|
||||
const styles = BackgroundGenerator.generateCss(config);
|
||||
|
||||
// Apply styles to element
|
||||
Object.entries(styles).forEach(([property, value]) => {
|
||||
element.style.setProperty(property, value);
|
||||
});
|
||||
|
||||
// Add to active backgrounds
|
||||
this._activeBackgrounds.update(backgrounds => {
|
||||
const newMap = new Map(backgrounds);
|
||||
newMap.set(backgroundId, {
|
||||
active: true,
|
||||
config,
|
||||
element
|
||||
});
|
||||
return newMap;
|
||||
});
|
||||
|
||||
return backgroundId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a full-screen background
|
||||
*/
|
||||
applyFullScreenBackground(config: BackgroundConfig, options?: Partial<BackgroundOptions>): string {
|
||||
const backgroundId = this.generateId();
|
||||
const element = this.createFullScreenElement(options);
|
||||
|
||||
const styles = BackgroundGenerator.generateCss(config);
|
||||
Object.entries(styles).forEach(([property, value]) => {
|
||||
element.style.setProperty(property, value);
|
||||
});
|
||||
|
||||
document.body.appendChild(element);
|
||||
|
||||
this._activeBackgrounds.update(backgrounds => {
|
||||
const newMap = new Map(backgrounds);
|
||||
newMap.set(backgroundId, {
|
||||
active: true,
|
||||
config,
|
||||
element
|
||||
});
|
||||
return newMap;
|
||||
});
|
||||
|
||||
return backgroundId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing background
|
||||
*/
|
||||
updateBackground(id: string, config: BackgroundConfig): boolean {
|
||||
const backgroundState = this._activeBackgrounds().get(id);
|
||||
if (!backgroundState || !backgroundState.element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const styles = BackgroundGenerator.generateCss(config);
|
||||
Object.entries(styles).forEach(([property, value]) => {
|
||||
backgroundState.element!.style.setProperty(property, value);
|
||||
});
|
||||
|
||||
this._activeBackgrounds.update(backgrounds => {
|
||||
const newMap = new Map(backgrounds);
|
||||
const existing = newMap.get(id);
|
||||
if (existing) {
|
||||
existing.config = config;
|
||||
newMap.set(id, existing);
|
||||
}
|
||||
return newMap;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a background
|
||||
*/
|
||||
removeBackground(id: string): boolean {
|
||||
const backgroundState = this._activeBackgrounds().get(id);
|
||||
if (!backgroundState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove full-screen element if it was created by this service
|
||||
if (backgroundState.element?.classList.contains('ui-background-fullscreen')) {
|
||||
backgroundState.element.remove();
|
||||
} else if (backgroundState.element) {
|
||||
// Clear inline styles for regular elements
|
||||
this.clearElementStyles(backgroundState.element);
|
||||
}
|
||||
|
||||
this._activeBackgrounds.update(backgrounds => {
|
||||
const newMap = new Map(backgrounds);
|
||||
newMap.delete(id);
|
||||
return newMap;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all backgrounds
|
||||
*/
|
||||
removeAllBackgrounds(): void {
|
||||
this._activeBackgrounds().forEach((state, id) => {
|
||||
this.removeBackground(id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get background state
|
||||
*/
|
||||
getBackground(id: string): BackgroundState | undefined {
|
||||
return this._activeBackgrounds().get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate CSS for a configuration without applying it
|
||||
*/
|
||||
generateCss(config: BackgroundConfig): { [key: string]: string } {
|
||||
return BackgroundGenerator.generateCss(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a background ID
|
||||
*/
|
||||
private generateId(): string {
|
||||
return `bg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a full-screen background element
|
||||
*/
|
||||
private createFullScreenElement(options?: Partial<BackgroundOptions>): HTMLElement {
|
||||
const element = document.createElement('div');
|
||||
element.className = `ui-background-fullscreen ${options?.className || ''}`.trim();
|
||||
|
||||
// Base full-screen styles
|
||||
element.style.position = 'fixed';
|
||||
element.style.top = '0';
|
||||
element.style.left = '0';
|
||||
element.style.width = '100%';
|
||||
element.style.height = '100%';
|
||||
element.style.pointerEvents = 'none';
|
||||
element.style.zIndex = (options?.zIndex || -1).toString();
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear background-related styles from an element
|
||||
*/
|
||||
private clearElementStyles(element: HTMLElement): void {
|
||||
const propertiesToClear = [
|
||||
'background',
|
||||
'background-image',
|
||||
'background-color',
|
||||
'background-size',
|
||||
'background-position',
|
||||
'background-repeat',
|
||||
'background-attachment',
|
||||
'backdrop-filter',
|
||||
'opacity',
|
||||
'animation'
|
||||
];
|
||||
|
||||
propertiesToClear.forEach(property => {
|
||||
element.style.removeProperty(property);
|
||||
});
|
||||
}
|
||||
}
|
||||
1
projects/ui-backgrounds/src/lib/services/index.ts
Normal file
1
projects/ui-backgrounds/src/lib/services/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './background.service';
|
||||
142
projects/ui-backgrounds/src/lib/types/background.types.ts
Normal file
142
projects/ui-backgrounds/src/lib/types/background.types.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
export type BackgroundType =
|
||||
| 'solid'
|
||||
| 'linear-gradient'
|
||||
| 'radial-gradient'
|
||||
| 'conic-gradient'
|
||||
| 'pattern'
|
||||
| 'image'
|
||||
| 'animated'
|
||||
| 'mesh'
|
||||
| 'noise'
|
||||
| 'glass';
|
||||
|
||||
export type PatternType =
|
||||
| 'dots'
|
||||
| 'grid'
|
||||
| 'stripes'
|
||||
| 'diagonal-stripes'
|
||||
| 'chevron'
|
||||
| 'waves'
|
||||
| 'hexagon'
|
||||
| 'triangles'
|
||||
| 'checkerboard'
|
||||
| 'circles'
|
||||
| 'crosshatch'
|
||||
| 'polka-dots';
|
||||
|
||||
export type GradientDirection =
|
||||
| 'to-top'
|
||||
| 'to-top-right'
|
||||
| 'to-right'
|
||||
| 'to-bottom-right'
|
||||
| 'to-bottom'
|
||||
| 'to-bottom-left'
|
||||
| 'to-left'
|
||||
| 'to-top-left';
|
||||
|
||||
export interface ColorStop {
|
||||
color: string;
|
||||
position?: string | number;
|
||||
}
|
||||
|
||||
export interface SolidBackgroundConfig {
|
||||
type: 'solid';
|
||||
color: string;
|
||||
}
|
||||
|
||||
export interface LinearGradientConfig {
|
||||
type: 'linear-gradient';
|
||||
direction?: GradientDirection | string;
|
||||
colors: ColorStop[];
|
||||
}
|
||||
|
||||
export interface RadialGradientConfig {
|
||||
type: 'radial-gradient';
|
||||
shape?: 'circle' | 'ellipse';
|
||||
size?: 'closest-side' | 'closest-corner' | 'farthest-side' | 'farthest-corner';
|
||||
position?: string;
|
||||
colors: ColorStop[];
|
||||
}
|
||||
|
||||
export interface ConicGradientConfig {
|
||||
type: 'conic-gradient';
|
||||
angle?: string | number;
|
||||
position?: string;
|
||||
colors: ColorStop[];
|
||||
}
|
||||
|
||||
export interface PatternConfig {
|
||||
type: 'pattern';
|
||||
pattern: PatternType;
|
||||
primaryColor?: string;
|
||||
secondaryColor?: string;
|
||||
size?: string | number;
|
||||
opacity?: number;
|
||||
}
|
||||
|
||||
export interface ImageBackgroundConfig {
|
||||
type: 'image';
|
||||
url: string;
|
||||
size?: 'auto' | 'cover' | 'contain' | string;
|
||||
position?: string;
|
||||
repeat?: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';
|
||||
attachment?: 'scroll' | 'fixed' | 'local';
|
||||
opacity?: number;
|
||||
}
|
||||
|
||||
export interface AnimatedBackgroundConfig {
|
||||
type: 'animated';
|
||||
baseConfig: LinearGradientConfig | RadialGradientConfig | ConicGradientConfig | PatternConfig;
|
||||
duration?: string;
|
||||
timing?: string;
|
||||
iteration?: 'infinite' | number;
|
||||
}
|
||||
|
||||
export interface MeshGradientConfig {
|
||||
type: 'mesh';
|
||||
colors: string[];
|
||||
complexity?: 'low' | 'medium' | 'high';
|
||||
seed?: number;
|
||||
}
|
||||
|
||||
export interface NoiseConfig {
|
||||
type: 'noise';
|
||||
baseColor?: string;
|
||||
intensity?: number;
|
||||
scale?: number;
|
||||
opacity?: number;
|
||||
}
|
||||
|
||||
export interface GlassConfig {
|
||||
type: 'glass';
|
||||
backdrop?: 'blur' | 'saturate' | 'both';
|
||||
intensity?: number;
|
||||
tint?: string;
|
||||
opacity?: number;
|
||||
}
|
||||
|
||||
export type BackgroundConfig =
|
||||
| SolidBackgroundConfig
|
||||
| LinearGradientConfig
|
||||
| RadialGradientConfig
|
||||
| ConicGradientConfig
|
||||
| PatternConfig
|
||||
| ImageBackgroundConfig
|
||||
| AnimatedBackgroundConfig
|
||||
| MeshGradientConfig
|
||||
| NoiseConfig
|
||||
| GlassConfig;
|
||||
|
||||
export interface BackgroundOptions {
|
||||
config: BackgroundConfig;
|
||||
zIndex?: number;
|
||||
fullScreen?: boolean;
|
||||
responsive?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface BackgroundState {
|
||||
active: boolean;
|
||||
config?: BackgroundConfig;
|
||||
element?: HTMLElement;
|
||||
}
|
||||
1
projects/ui-backgrounds/src/lib/types/index.ts
Normal file
1
projects/ui-backgrounds/src/lib/types/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './background.types';
|
||||
234
projects/ui-backgrounds/src/lib/utils/background-generator.ts
Normal file
234
projects/ui-backgrounds/src/lib/utils/background-generator.ts
Normal file
@@ -0,0 +1,234 @@
|
||||
import {
|
||||
BackgroundConfig,
|
||||
ColorStop,
|
||||
LinearGradientConfig,
|
||||
RadialGradientConfig,
|
||||
ConicGradientConfig,
|
||||
PatternConfig,
|
||||
ImageBackgroundConfig,
|
||||
SolidBackgroundConfig,
|
||||
AnimatedBackgroundConfig,
|
||||
MeshGradientConfig,
|
||||
NoiseConfig,
|
||||
GlassConfig
|
||||
} from '../types/background.types';
|
||||
|
||||
export class BackgroundGenerator {
|
||||
|
||||
static generateCss(config: BackgroundConfig): { [key: string]: string } {
|
||||
switch (config.type) {
|
||||
case 'solid':
|
||||
return this.generateSolid(config);
|
||||
case 'linear-gradient':
|
||||
return this.generateLinearGradient(config);
|
||||
case 'radial-gradient':
|
||||
return this.generateRadialGradient(config);
|
||||
case 'conic-gradient':
|
||||
return this.generateConicGradient(config);
|
||||
case 'pattern':
|
||||
return this.generatePattern(config);
|
||||
case 'image':
|
||||
return this.generateImage(config);
|
||||
case 'animated':
|
||||
return this.generateAnimated(config);
|
||||
case 'mesh':
|
||||
return this.generateMesh(config);
|
||||
case 'noise':
|
||||
return this.generateNoise(config);
|
||||
case 'glass':
|
||||
return this.generateGlass(config);
|
||||
default:
|
||||
return { background: 'transparent' };
|
||||
}
|
||||
}
|
||||
|
||||
private static generateSolid(config: SolidBackgroundConfig): { [key: string]: string } {
|
||||
return {
|
||||
background: config.color,
|
||||
'background-size': 'cover',
|
||||
'background-position': 'center',
|
||||
'background-repeat': 'no-repeat'
|
||||
};
|
||||
}
|
||||
|
||||
private static generateLinearGradient(config: LinearGradientConfig): { [key: string]: string } {
|
||||
const direction = config.direction || 'to bottom';
|
||||
const colorStops = this.formatColorStops(config.colors);
|
||||
|
||||
return {
|
||||
background: `linear-gradient(${direction}, ${colorStops})`,
|
||||
'background-size': 'cover',
|
||||
'background-position': 'center',
|
||||
'background-repeat': 'no-repeat'
|
||||
};
|
||||
}
|
||||
|
||||
private static generateRadialGradient(config: RadialGradientConfig): { [key: string]: string } {
|
||||
const shape = config.shape || 'ellipse';
|
||||
const size = config.size || 'farthest-corner';
|
||||
const position = config.position || 'center';
|
||||
const colorStops = this.formatColorStops(config.colors);
|
||||
|
||||
return {
|
||||
background: `radial-gradient(${shape} ${size} at ${position}, ${colorStops})`,
|
||||
'background-size': 'cover',
|
||||
'background-position': 'center',
|
||||
'background-repeat': 'no-repeat'
|
||||
};
|
||||
}
|
||||
|
||||
private static generateConicGradient(config: ConicGradientConfig): { [key: string]: string } {
|
||||
const angle = config.angle ? `from ${config.angle}deg` : '';
|
||||
const position = config.position ? `at ${config.position}` : '';
|
||||
const colorStops = this.formatColorStops(config.colors);
|
||||
|
||||
return {
|
||||
background: `conic-gradient(${angle} ${position}, ${colorStops})`,
|
||||
'background-size': 'cover',
|
||||
'background-position': 'center',
|
||||
'background-repeat': 'no-repeat'
|
||||
};
|
||||
}
|
||||
|
||||
private static generatePattern(config: PatternConfig): { [key: string]: string } {
|
||||
const primaryColor = config.primaryColor || '#000000';
|
||||
const secondaryColor = config.secondaryColor || '#ffffff';
|
||||
const size = typeof config.size === 'number' ? `${config.size}px` : (config.size || '20px');
|
||||
const opacity = config.opacity || 1;
|
||||
|
||||
const patternCss = this.getPatternCss(config.pattern, primaryColor, secondaryColor, size);
|
||||
|
||||
return {
|
||||
background: patternCss,
|
||||
opacity: opacity.toString(),
|
||||
'background-size': size,
|
||||
'background-repeat': 'repeat'
|
||||
};
|
||||
}
|
||||
|
||||
private static generateImage(config: ImageBackgroundConfig): { [key: string]: string } {
|
||||
const styles: { [key: string]: string } = {
|
||||
'background-image': `url(${config.url})`,
|
||||
'background-size': config.size || 'cover',
|
||||
'background-position': config.position || 'center',
|
||||
'background-repeat': config.repeat || 'no-repeat'
|
||||
};
|
||||
|
||||
if (config.attachment) {
|
||||
styles['background-attachment'] = config.attachment;
|
||||
}
|
||||
|
||||
if (config.opacity !== undefined) {
|
||||
styles['opacity'] = config.opacity.toString();
|
||||
}
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
private static generateAnimated(config: AnimatedBackgroundConfig): { [key: string]: string } {
|
||||
const baseStyles = this.generateCss(config.baseConfig);
|
||||
const duration = config.duration || '5s';
|
||||
const timing = config.timing || 'ease-in-out';
|
||||
const iteration = config.iteration === 'infinite' ? 'infinite' : (config.iteration || 1).toString();
|
||||
|
||||
return {
|
||||
...baseStyles,
|
||||
animation: `background-animation ${duration} ${timing} ${iteration}`,
|
||||
};
|
||||
}
|
||||
|
||||
private static generateMesh(config: MeshGradientConfig): { [key: string]: string } {
|
||||
// Generate mesh gradient using multiple radial gradients
|
||||
const colors = config.colors;
|
||||
const complexity = config.complexity || 'medium';
|
||||
|
||||
// Create multiple overlapping radial gradients
|
||||
const gradients = this.generateMeshGradients(colors, complexity);
|
||||
|
||||
return {
|
||||
background: gradients.join(', '),
|
||||
'background-size': '400% 400%',
|
||||
animation: 'mesh-animation 15s ease infinite'
|
||||
};
|
||||
}
|
||||
|
||||
private static generateNoise(config: NoiseConfig): { [key: string]: string } {
|
||||
const baseColor = config.baseColor || '#000000';
|
||||
const intensity = config.intensity || 0.5;
|
||||
const scale = config.scale || 100;
|
||||
const opacity = config.opacity || 1;
|
||||
|
||||
// Create noise effect using CSS filters and patterns
|
||||
return {
|
||||
background: baseColor,
|
||||
'background-image': `url("data:image/svg+xml,%3Csvg viewBox='0 0 ${scale} ${scale}' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)' opacity='${intensity}'/%3E%3C/svg%3E")`,
|
||||
opacity: opacity.toString()
|
||||
};
|
||||
}
|
||||
|
||||
private static generateGlass(config: GlassConfig): { [key: string]: string } {
|
||||
const intensity = config.intensity || 10;
|
||||
const tint = config.tint || 'rgba(255, 255, 255, 0.1)';
|
||||
const opacity = config.opacity || 0.8;
|
||||
|
||||
const styles: { [key: string]: string } = {
|
||||
background: tint,
|
||||
opacity: opacity.toString(),
|
||||
'backdrop-filter': `blur(${intensity}px)`
|
||||
};
|
||||
|
||||
if (config.backdrop === 'saturate' || config.backdrop === 'both') {
|
||||
styles['backdrop-filter'] += ` saturate(150%)`;
|
||||
}
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
private static formatColorStops(colors: ColorStop[]): string {
|
||||
return colors.map(stop => {
|
||||
if (stop.position !== undefined) {
|
||||
const position = typeof stop.position === 'number' ? `${stop.position}%` : stop.position;
|
||||
return `${stop.color} ${position}`;
|
||||
}
|
||||
return stop.color;
|
||||
}).join(', ');
|
||||
}
|
||||
|
||||
private static getPatternCss(pattern: string, primary: string, secondary: string, size: string): string {
|
||||
const patterns: { [key: string]: string } = {
|
||||
'dots': `radial-gradient(circle, ${primary} 20%, transparent 20%)`,
|
||||
'grid': `linear-gradient(${primary} 1px, transparent 1px), linear-gradient(90deg, ${primary} 1px, transparent 1px)`,
|
||||
'stripes': `linear-gradient(45deg, ${primary} 25%, transparent 25%, transparent 50%, ${primary} 50%, ${primary} 75%, transparent 75%)`,
|
||||
'diagonal-stripes': `linear-gradient(45deg, ${primary} 25%, transparent 25%, transparent 50%, ${primary} 50%, ${primary} 75%, transparent 75%)`,
|
||||
'chevron': `linear-gradient(45deg, ${primary} 25%, transparent 25%), linear-gradient(-45deg, ${primary} 25%, transparent 25%)`,
|
||||
'waves': `radial-gradient(circle at 50% 100%, transparent 40%, ${primary} 40%, ${primary} 60%, transparent 60%)`,
|
||||
'hexagon': `radial-gradient(circle at 50% 0%, transparent 40%, ${primary} 40%, ${primary} 60%, transparent 60%)`,
|
||||
'triangles': `linear-gradient(60deg, ${primary} 25%, transparent 25%), linear-gradient(120deg, ${primary} 25%, transparent 25%)`,
|
||||
'checkerboard': `linear-gradient(45deg, ${primary} 25%, transparent 25%, transparent 75%, ${primary} 75%), linear-gradient(45deg, ${primary} 25%, transparent 25%, transparent 75%, ${primary} 75%)`,
|
||||
'circles': `radial-gradient(circle, ${primary} 40%, transparent 40%)`,
|
||||
'crosshatch': `linear-gradient(0deg, ${primary} 1px, transparent 1px), linear-gradient(90deg, ${primary} 1px, transparent 1px), linear-gradient(45deg, ${primary} 1px, transparent 1px), linear-gradient(-45deg, ${primary} 1px, transparent 1px)`,
|
||||
'polka-dots': `radial-gradient(circle, ${primary} 25%, transparent 25%)`
|
||||
};
|
||||
|
||||
return patterns[pattern] || patterns['dots'];
|
||||
}
|
||||
|
||||
private static generateMeshGradients(colors: string[], complexity: string): string[] {
|
||||
const gradientCount = complexity === 'high' ? 6 : complexity === 'medium' ? 4 : 2;
|
||||
const gradients: string[] = [];
|
||||
|
||||
for (let i = 0; i < gradientCount; i++) {
|
||||
const color1 = colors[i % colors.length];
|
||||
const color2 = colors[(i + 1) % colors.length];
|
||||
const x = Math.random() * 100;
|
||||
const y = Math.random() * 100;
|
||||
const size = 50 + Math.random() * 50;
|
||||
|
||||
gradients.push(
|
||||
`radial-gradient(${size}% ${size}% at ${x}% ${y}%, ${color1}, transparent)`
|
||||
);
|
||||
}
|
||||
|
||||
return gradients;
|
||||
}
|
||||
}
|
||||
1
projects/ui-backgrounds/src/lib/utils/index.ts
Normal file
1
projects/ui-backgrounds/src/lib/utils/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './background-generator';
|
||||
18
projects/ui-backgrounds/src/public-api.ts
Normal file
18
projects/ui-backgrounds/src/public-api.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Public API Surface of ui-backgrounds
|
||||
*/
|
||||
|
||||
// Types
|
||||
export * from './lib/types/index';
|
||||
|
||||
// Services
|
||||
export * from './lib/services/index';
|
||||
|
||||
// Directives
|
||||
export * from './lib/directives/index';
|
||||
|
||||
// Components
|
||||
export * from './lib/components/index';
|
||||
|
||||
// Utils
|
||||
export * from './lib/utils/index';
|
||||
113
projects/ui-backgrounds/src/styles/_animations.scss
Normal file
113
projects/ui-backgrounds/src/styles/_animations.scss
Normal file
@@ -0,0 +1,113 @@
|
||||
// Animation keyframes for ui-backgrounds library
|
||||
|
||||
// Basic gradient animation
|
||||
@keyframes ui-background-animation {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
// Mesh gradient animation
|
||||
@keyframes ui-mesh-animation {
|
||||
0%, 100% {
|
||||
background-position: 0% 0%;
|
||||
}
|
||||
25% {
|
||||
background-position: 100% 0%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
75% {
|
||||
background-position: 0% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// Floating animation for patterns
|
||||
@keyframes ui-pattern-float {
|
||||
0%, 100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
// Rotation animation
|
||||
@keyframes ui-background-rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
// Scale animation
|
||||
@keyframes ui-background-scale {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
// Pulse animation
|
||||
@keyframes ui-background-pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
// Color shifting animation
|
||||
@keyframes ui-background-hue-shift {
|
||||
0% {
|
||||
filter: hue-rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
filter: hue-rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
// Blur animation for glass effects
|
||||
@keyframes ui-background-blur-pulse {
|
||||
0%, 100% {
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
50% {
|
||||
backdrop-filter: blur(20px);
|
||||
}
|
||||
}
|
||||
|
||||
// Slide animation
|
||||
@keyframes ui-background-slide {
|
||||
0% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Wave animation
|
||||
@keyframes ui-background-wave {
|
||||
0%, 100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
25% {
|
||||
background-position: 50% 0%;
|
||||
}
|
||||
75% {
|
||||
background-position: 50% 100%;
|
||||
}
|
||||
}
|
||||
180
projects/ui-backgrounds/src/styles/_base.scss
Normal file
180
projects/ui-backgrounds/src/styles/_base.scss
Normal file
@@ -0,0 +1,180 @@
|
||||
// Base styles for ui-backgrounds library
|
||||
|
||||
// Import animations
|
||||
@import 'animations';
|
||||
|
||||
// Base background component styles
|
||||
.ui-background {
|
||||
position: relative;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
// Ensure proper layering
|
||||
z-index: 0;
|
||||
|
||||
&--fullscreen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Type-specific styles
|
||||
.ui-background--solid {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.ui-background--gradient {
|
||||
// Base gradient styles
|
||||
&.ui-background--linear-gradient {
|
||||
background-size: 200% 200%;
|
||||
}
|
||||
|
||||
&.ui-background--radial-gradient {
|
||||
background-size: 200% 200%;
|
||||
}
|
||||
|
||||
&.ui-background--conic-gradient {
|
||||
background-size: 200% 200%;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-background--pattern {
|
||||
background-repeat: repeat;
|
||||
|
||||
&.ui-background--pattern-dots {
|
||||
// Dots pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-grid {
|
||||
// Grid pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-stripes {
|
||||
// Stripes pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-diagonal-stripes {
|
||||
// Diagonal stripes pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-chevron {
|
||||
// Chevron pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-waves {
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
&.ui-background--pattern-hexagon {
|
||||
// Hexagon pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-triangles {
|
||||
// Triangles pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-checkerboard {
|
||||
// Checkerboard pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-circles {
|
||||
// Circles pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-crosshatch {
|
||||
// Crosshatch pattern specific styles
|
||||
}
|
||||
|
||||
&.ui-background--pattern-polka-dots {
|
||||
// Polka dots pattern specific styles
|
||||
}
|
||||
}
|
||||
|
||||
.ui-background--image {
|
||||
// Image background specific styles
|
||||
}
|
||||
|
||||
.ui-background--animated {
|
||||
// Base animation styles
|
||||
background-size: 200% 200%;
|
||||
|
||||
// Apply default animation
|
||||
animation: ui-background-animation 5s ease-in-out infinite;
|
||||
|
||||
// Respect reduced motion preferences
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-background--mesh {
|
||||
background-size: 400% 400%;
|
||||
animation: ui-mesh-animation 15s ease infinite;
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-background--noise {
|
||||
// Noise background specific styles
|
||||
}
|
||||
|
||||
.ui-background--glass {
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px); // Safari support
|
||||
|
||||
// Fallback for browsers that don't support backdrop-filter
|
||||
@supports not (backdrop-filter: blur()) {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive behavior
|
||||
@media (max-width: 768px) {
|
||||
.ui-background--animated,
|
||||
.ui-background--mesh {
|
||||
// Disable complex animations on mobile for performance
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
animation-duration: 10s; // Slower animations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// High contrast mode support
|
||||
@media (prefers-contrast: high) {
|
||||
.ui-background {
|
||||
filter: contrast(1.2);
|
||||
}
|
||||
|
||||
.ui-background--glass {
|
||||
backdrop-filter: none;
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
}
|
||||
}
|
||||
|
||||
// Print styles
|
||||
@media print {
|
||||
.ui-background {
|
||||
background: none !important;
|
||||
backdrop-filter: none !important;
|
||||
animation: none !important;
|
||||
}
|
||||
|
||||
.ui-background--fullscreen {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Dark mode considerations
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.ui-background--glass {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
140
projects/ui-backgrounds/src/styles/_mixins.scss
Normal file
140
projects/ui-backgrounds/src/styles/_mixins.scss
Normal file
@@ -0,0 +1,140 @@
|
||||
// Background Mixins for ui-backgrounds library
|
||||
|
||||
// Base background mixin
|
||||
@mixin ui-background-base() {
|
||||
position: relative;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
// Full screen background mixin
|
||||
@mixin ui-background-fullscreen($z-index: -1) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: $z-index;
|
||||
}
|
||||
|
||||
// Solid color background
|
||||
@mixin ui-background-solid($color) {
|
||||
background-color: $color;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
// Linear gradient background
|
||||
@mixin ui-background-linear-gradient($direction: 'to bottom', $colors...) {
|
||||
background: linear-gradient(#{$direction}, $colors);
|
||||
}
|
||||
|
||||
// Radial gradient background
|
||||
@mixin ui-background-radial-gradient($shape: 'ellipse', $size: 'farthest-corner', $position: 'center', $colors...) {
|
||||
background: radial-gradient(#{$shape} #{$size} at #{$position}, $colors);
|
||||
}
|
||||
|
||||
// Conic gradient background
|
||||
@mixin ui-background-conic-gradient($angle: 0deg, $position: 'center', $colors...) {
|
||||
background: conic-gradient(from #{$angle} at #{$position}, $colors);
|
||||
}
|
||||
|
||||
// Pattern backgrounds
|
||||
@mixin ui-pattern-dots($primary: #000, $secondary: transparent, $size: 20px) {
|
||||
background-image: radial-gradient(circle, #{$primary} 20%, #{$secondary} 20%);
|
||||
background-size: $size $size;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
@mixin ui-pattern-grid($color: #000, $size: 20px, $line-width: 1px) {
|
||||
background-image:
|
||||
linear-gradient(#{$color} #{$line-width}, transparent #{$line-width}),
|
||||
linear-gradient(90deg, #{$color} #{$line-width}, transparent #{$line-width});
|
||||
background-size: $size $size;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
@mixin ui-pattern-stripes($primary: #000, $secondary: transparent, $size: 20px) {
|
||||
background-image: linear-gradient(45deg, #{$primary} 25%, #{$secondary} 25%, #{$secondary} 50%, #{$primary} 50%, #{$primary} 75%, #{$secondary} 75%);
|
||||
background-size: $size $size;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
@mixin ui-pattern-diagonal-stripes($primary: #000, $secondary: transparent, $size: 20px) {
|
||||
background-image: linear-gradient(-45deg, #{$primary} 25%, #{$secondary} 25%, #{$secondary} 50%, #{$primary} 50%, #{$primary} 75%, #{$secondary} 75%);
|
||||
background-size: $size $size;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
@mixin ui-pattern-chevron($primary: #000, $secondary: transparent, $size: 20px) {
|
||||
background-image:
|
||||
linear-gradient(45deg, #{$primary} 25%, #{$secondary} 25%),
|
||||
linear-gradient(-45deg, #{$primary} 25%, #{$secondary} 25%);
|
||||
background-size: $size $size;
|
||||
background-repeat: repeat;
|
||||
background-position: 0 0, 0 ($size / 2);
|
||||
}
|
||||
|
||||
@mixin ui-pattern-waves($primary: #000, $secondary: transparent, $size: 40px) {
|
||||
background-image: radial-gradient(circle at 50% 100%, #{$secondary} 40%, #{$primary} 40%, #{$primary} 60%, #{$secondary} 60%);
|
||||
background-size: $size ($size / 2);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
@mixin ui-pattern-checkerboard($primary: #000, $secondary: #fff, $size: 20px) {
|
||||
background-image:
|
||||
linear-gradient(45deg, #{$primary} 25%, transparent 25%, transparent 75%, #{$primary} 75%),
|
||||
linear-gradient(45deg, #{$primary} 25%, transparent 25%, transparent 75%, #{$primary} 75%);
|
||||
background-color: $secondary;
|
||||
background-size: $size $size;
|
||||
background-position: 0 0, ($size / 2) ($size / 2);
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
// Animated backgrounds
|
||||
@mixin ui-background-animated($duration: 5s, $timing: ease-in-out, $iteration: infinite) {
|
||||
animation: ui-background-animation $duration $timing $iteration;
|
||||
}
|
||||
|
||||
@mixin ui-background-mesh-animated($duration: 15s) {
|
||||
background-size: 400% 400%;
|
||||
animation: ui-mesh-animation $duration ease infinite;
|
||||
}
|
||||
|
||||
// Glass/blur backgrounds
|
||||
@mixin ui-background-glass($blur: 10px, $tint: rgba(255, 255, 255, 0.1), $opacity: 0.8) {
|
||||
background: $tint;
|
||||
backdrop-filter: blur($blur);
|
||||
opacity: $opacity;
|
||||
}
|
||||
|
||||
// Responsive background utilities
|
||||
@mixin ui-background-responsive($mobile-bg, $tablet-bg: null, $desktop-bg: null) {
|
||||
background: $mobile-bg;
|
||||
|
||||
@if $tablet-bg {
|
||||
@media (min-width: 768px) {
|
||||
background: $tablet-bg;
|
||||
}
|
||||
}
|
||||
|
||||
@if $desktop-bg {
|
||||
@media (min-width: 1024px) {
|
||||
background: $desktop-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accessibility utilities
|
||||
@mixin ui-background-high-contrast() {
|
||||
@media (prefers-contrast: high) {
|
||||
filter: contrast(1.5);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin ui-background-reduced-motion() {
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
9
projects/ui-backgrounds/src/styles/index.scss
Normal file
9
projects/ui-backgrounds/src/styles/index.scss
Normal file
@@ -0,0 +1,9 @@
|
||||
// Main entry point for ui-backgrounds styles
|
||||
|
||||
// Import base components
|
||||
@import 'mixins';
|
||||
@import 'animations';
|
||||
@import 'base';
|
||||
|
||||
// Export mixins for external use
|
||||
// Users can import this file to get access to all background mixins and styles
|
||||
15
projects/ui-backgrounds/tsconfig.lib.json
Normal file
15
projects/ui-backgrounds/tsconfig.lib.json
Normal file
@@ -0,0 +1,15 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/lib",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
11
projects/ui-backgrounds/tsconfig.lib.prod.json
Normal file
11
projects/ui-backgrounds/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,11 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
15
projects/ui-backgrounds/tsconfig.spec.json
Normal file
15
projects/ui-backgrounds/tsconfig.spec.json
Normal file
@@ -0,0 +1,15 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user