Files
ui-essentials/src/lib/components/feedback/skeleton-loader/skeleton-loader.component.scss
Jules 0a0cade343 Initial commit - Angular library: ui-essentials
🎯 Implementation Complete!

This library has been extracted from the monorepo and is ready for Git submodule distribution.

Features:
- Standardized SCSS imports (no relative paths)
- Optimized public-api.ts exports
- Independent Angular library structure
- Ready for consumer integration as submodule

🚀 Generated with Claude Code (https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-11 21:12:46 +10:00

293 lines
4.6 KiB
SCSS

@use 'ui-design-system/src/styles/semantic/index' as *;
.ui-skeleton-loader {
display: block;
width: 100%;
overflow: hidden;
position: relative;
background: $semantic-color-surface-variant;
// Core structure
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.2),
transparent
);
animation: shimmer 2s ease-in-out infinite;
transform: translateX(-100%);
}
// Size variants
&--xs {
height: 0.5rem;
border-radius: 0.125rem;
}
&--sm {
height: 0.75rem;
border-radius: 0.25rem;
}
&--md {
height: 1rem;
border-radius: 0.375rem;
}
&--lg {
height: 1.25rem;
border-radius: 0.5rem;
}
&--xl {
height: 1.5rem;
border-radius: 0.5rem;
}
// Shape variants
&--text {
height: 1.25rem;
border-radius: 0.25rem;
}
&--heading {
height: 1.75rem;
border-radius: 0.25rem;
}
&--avatar {
border-radius: 50%;
aspect-ratio: 1;
&.ui-skeleton-loader--xs { width: 1rem; }
&.ui-skeleton-loader--sm { width: 1.5rem; }
&.ui-skeleton-loader--md { width: 2rem; }
&.ui-skeleton-loader--lg { width: 2.5rem; }
&.ui-skeleton-loader--xl { width: 3rem; }
}
&--card {
height: 200px;
border-radius: 0.5rem;
}
&--button {
height: 2.5rem;
width: 120px;
border-radius: 0.375rem;
}
&--image {
aspect-ratio: 16/9;
border-radius: 0.375rem;
}
&--circle {
border-radius: 50%;
aspect-ratio: 1;
}
&--rounded {
border-radius: 0.375rem;
}
&--square {
border-radius: 0;
}
// Animation variants
&--pulse {
&::after {
display: none;
}
animation: pulse 1.5s ease-in-out infinite alternate;
}
&--wave {
&::after {
background: linear-gradient(
90deg,
transparent 0%,
rgba(255, 255, 255, 0.4) 50%,
transparent 100%
);
animation: wave 2s ease-in-out infinite;
}
}
&--shimmer {
// Default shimmer animation (already applied)
}
// Width variants
&--w-25 { width: 25%; }
&--w-50 { width: 50%; }
&--w-75 { width: 75%; }
&--w-full { width: 100%; }
// State variants
&--loading {
opacity: 1;
}
&--loaded {
opacity: 0;
transition: opacity 0.3s ease;
}
// Dark mode support
:host-context(.dark-theme) & {
background: #374151;
&::after {
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.1),
transparent
);
}
}
// High contrast mode
@media (prefers-contrast: high) {
background: #6b7280;
&::after {
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.6),
transparent
);
}
}
// Reduced motion
@media (prefers-reduced-motion: reduce) {
&::after {
animation: none;
}
&.ui-skeleton-loader--pulse {
animation: none;
}
}
}
// Skeleton group for multiple skeleton items
.ui-skeleton-group {
display: flex;
flex-direction: column;
gap: 0.75rem;
// Horizontal group
&--horizontal {
flex-direction: row;
align-items: center;
}
// Grid group
&--grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
// Avatar with text group
&--avatar-text {
flex-direction: row;
align-items: flex-start;
gap: 0.75rem;
.ui-skeleton-loader--avatar {
flex-shrink: 0;
}
.ui-skeleton-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
}
// Card group
&--card {
.ui-skeleton-loader {
&:first-child {
height: 180px;
border-radius: 0.5rem 0.5rem 0 0;
}
&:not(:first-child) {
margin: 0.75rem;
height: 1rem;
&:last-child {
width: 60%;
}
}
}
}
// Table group
&--table {
.ui-skeleton-loader {
height: 1.25rem;
&:first-child {
width: 30%;
}
&:nth-child(2) {
width: 50%;
}
&:last-child {
width: 20%;
}
}
}
}
// Animations
@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
@keyframes pulse {
0% {
opacity: 1;
}
100% {
opacity: 0.6;
}
}
@keyframes wave {
0% {
transform: translateX(-100%) scale(0.8);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: translateX(100%) scale(1.2);
opacity: 0;
}
}