From 695312f1bbfa4d907c00de57b251be0d37fa1744 Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Sun, 19 Jul 2026 23:19:08 +0400 Subject: [PATCH] fix(storefront): polish home Replace hardcoded loading text with skeleton state (app-skeleton) and plain empty-state text with shared EmptyStateComponent. Remove ~900 lines of dead CSS from two unused prior redesigns (.alt-* / .platform-*) that had no template references. Co-Authored-By: Claude Sonnet 5 --- src/app/pages/home/home.component.html | 15 +- src/app/pages/home/home.component.scss | 926 +------------------------ src/app/pages/home/home.component.ts | 5 +- 3 files changed, 25 insertions(+), 921 deletions(-) diff --git a/src/app/pages/home/home.component.html b/src/app/pages/home/home.component.html index 4b10b52..cccf949 100644 --- a/src/app/pages/home/home.component.html +++ b/src/app/pages/home/home.component.html @@ -1,11 +1,20 @@ @if (loading()) { -
-
Loading homepage...
+
+
+ +
+ @for (card of skeletonCards; track card) { + + } +
+
} @else if (pageModel()) { } @else {
-
{{ 'platform.emptyConfig' | translate }}
+
+ +
} diff --git a/src/app/pages/home/home.component.scss b/src/app/pages/home/home.component.scss index 5759c51..e0f0fbe 100644 --- a/src/app/pages/home/home.component.scss +++ b/src/app/pages/home/home.component.scss @@ -1,924 +1,16 @@ -// ========== SHARED ANIMATIONS ========== -@keyframes fadeIn { - from { opacity: 0; transform: translateY(10px); } - to { opacity: 1; transform: translateY(0); } +.home-loading__grid { + display: flex; + flex-direction: column; + gap: 24px; + padding-block: 24px; } -@keyframes fadeInUp { - from { opacity: 0; transform: translateY(30px); } - to { opacity: 1; transform: translateY(0); } -} - -@keyframes slideDown { - from { opacity: 0; transform: translateY(-30px); } - to { opacity: 1; transform: translateY(0); } -} - -@keyframes spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } -} - -// ========== alt HOME PAGE STYLES ========== -.alt-home { - min-height: calc(100vh - 200px); - animation: fadeIn 0.6s ease; -} - -.alt-hero { - background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%); - padding: 6rem 2rem; - text-align: center; - position: relative; - overflow: hidden; - - &.alt-hero-compact { - padding: 2.5rem 2rem; - - .alt-hero-title { - font-size: 2.2rem; - margin-bottom: 0.5rem; - } - - .alt-hero-subtitle { - font-size: 1.1rem; - margin-bottom: 1.5rem; - } - } - - &::before { - content: ''; - position: absolute; - width: 500px; - height: 500px; - background: rgba(255, 255, 255, 0.1); - border-radius: 50%; - top: -250px; - right: -250px; - } - - &::after { - content: ''; - position: absolute; - width: 300px; - height: 300px; - background: rgba(255, 255, 255, 0.05); - border-radius: 50%; - bottom: -150px; - left: -150px; - } -} - -.alt-hero-content { - max-width: 800px; - margin: 0 auto; - position: relative; - z-index: 1; -} - -.alt-hero-title { - font-size: 3.5rem; - font-weight: 700; - color: white; - margin: 0 0 1rem 0; - line-height: 1.2; - animation: slideDown 0.8s ease; -} - -.alt-hero-subtitle { - font-size: 1.5rem; - color: rgba(255, 255, 255, 0.95); - margin: 0 0 2.5rem 0; - animation: slideDown 0.8s ease 0.1s both; -} - -.alt-hero-btn { - display: inline-flex; - align-items: center; - gap: 0.75rem; - padding: 1rem 2.5rem; - background: white; - color: var(--primary-color); - text-decoration: none; - font-weight: 600; - font-size: 1.1rem; - border-radius: var(--radius-lg); - transition: all 0.3s; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); - animation: slideDown 0.8s ease 0.2s both; - - svg { - transition: transform 0.3s; - } - - &:hover { - transform: translateY(-3px); - box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2); - - svg { - transform: translateX(4px); - } - } -} - -.alt-loading { - text-align: center; - padding: 5rem 2rem; -} - -.alt-spinner { - width: 60px; - height: 60px; - border: 5px solid var(--bg-secondary); - border-top: 5px solid var(--primary-color); - border-radius: 50%; - animation: spin 1s linear infinite; - margin: 0 auto 1.5rem; -} - -.alt-error { - text-align: center; - padding: 5rem 2rem; - - .alt-error-icon { - font-size: 4rem; - margin-bottom: 1.5rem; - } - - h3 { - font-size: 1.75rem; - color: var(--text-primary); - margin: 0 0 1rem 0; - } - - p { - color: var(--text-secondary); - margin: 0 0 2rem 0; - } - - .alt-retry-btn { - padding: 0.875rem 2rem; - background: var(--primary-color); - color: white; - border: none; - border-radius: var(--radius-md); - font-weight: 600; - cursor: pointer; - transition: all 0.3s; - - &:hover { - background: var(--primary-hover); - transform: translateY(-2px); - box-shadow: var(--shadow-md); - } - } -} - -.alt-categories { - max-width: 1400px; - margin: 0 auto; - padding: 5rem 2rem; -} - -.alt-section-header { - text-align: center; - margin-bottom: 4rem; - - h2 { - font-size: 2.75rem; - font-weight: 700; - color: var(--text-primary); - margin: 0 0 1rem 0; - } - - p { - font-size: 1.2rem; - color: var(--text-secondary); - margin: 0; - } -} - -.alt-empty { - text-align: center; - padding: 5rem 2rem; - background: var(--bg-secondary); - border-radius: var(--radius-xl); - - .alt-empty-icon { - font-size: 5rem; - opacity: 0.5; - margin-bottom: 2rem; - } - - h3 { - font-size: 2rem; - color: var(--text-primary); - margin: 0 0 1rem 0; - } - - p { - font-size: 1.1rem; - color: var(--text-secondary); - margin: 0; - } -} - -.alt-categories-grid { +.home-loading__row { display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 2rem; -} - -.alt-category-card { - display: flex; - flex-direction: column; - background: white; - border-radius: var(--radius-lg); - overflow: hidden; - text-decoration: none; - box-shadow: var(--shadow-sm); - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); - border: 1px solid var(--border-color); - - &:hover { - transform: translateY(-8px); - box-shadow: var(--shadow-lg); - border-color: var(--primary-color); - - .alt-category-image { - img { - transform: scale(1.1); - } - - .alt-category-placeholder { - transform: scale(1.1); - } - } - - .alt-category-arrow { - transform: translateX(8px); - } - } -} - -.alt-category-image { - height: 200px; - overflow: hidden; - background: var(--bg-secondary); - display: flex; - align-items: center; - justify-content: center; - - img { - width: 100%; - height: 100%; - object-fit: contain; - background: white; - transition: transform 0.4s; - } - - .alt-category-placeholder { - width: 80px; - height: 80px; - border-radius: 50%; - background: var(--gradient-primary); - display: flex; - align-items: center; - justify-content: center; - transition: transform 0.4s; - - span { - font-size: 2rem; - font-weight: 700; - color: white; - } - } -} - -.alt-category-info { - padding: 1.5rem; - display: flex; - flex-direction: column; - align-items: flex-start; - - h3 { - font-size: 1.25rem; - font-weight: 600; - color: var(--text-primary); - margin: 0; - } - - .alt-category-count { - font-weight: 600; - font-size: clamp(11px, 1vw, 13px); - color: var(--text-secondary); - margin: 4px 0 0; - line-height: 1.2; - } -} - -@media (max-width: 968px) { - .alt-hero { - padding: 4rem 2rem; - } - - .alt-hero-title { - font-size: 2.5rem; - } - - .alt-hero-subtitle { - font-size: 1.2rem; - } - - .alt-categories-grid { - grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); - gap: 1.5rem; - } -} - -@media (max-width: 600px) { - .alt-hero { - padding: 3rem 1rem; - } - - .alt-hero-title { - font-size: 2rem; - } - - .alt-hero-subtitle { - font-size: 1.1rem; - } - - .alt-hero-btn { - padding: 0.875rem 2rem; - font-size: 1rem; - } - - .alt-categories { - padding: 3rem 1rem; - } - - .alt-section-header { - margin-bottom: 2.5rem; - - h2 { - font-size: 2rem; - } - - p { - font-size: 1rem; - } - } - - .alt-categories-grid { - grid-template-columns: 1fr; - gap: 1.25rem; - } - - .alt-category-card:hover { - transform: translateY(-4px); - } -} - -// ========== platform REDESIGN 2026 STYLES ========== -.platform-home { - width: 100%; - overflow-x: hidden; -} - -// Hero Section -.platform-hero { - position: relative; - width: 100%; - height: 600px; - background-image: url('/assets/images/hero_background_desktop.webp'); - background-size: cover; - background-position: center; - background-repeat: no-repeat; - overflow: hidden; - - // Mobile hero image - @media (max-width: 768px) { - background-image: url('/assets/images/hero_background_mobile.webp'); - } -} - -.platform-hero-overlay { - position: relative; - width: 100%; - height: 100%; - background: linear-gradient( - to right, - rgba(255, 255, 255, 0.1) 10%, - rgba(255, 255, 255, 0.1) 10%, - rgba(255, 255, 255, 0.1) 15%); - display: flex; - align-items: center; - padding: 0 56px; -} - -.platform-hero-content { - max-width: 600px; - display: flex; - flex-direction: column; - gap: 12px; - animation: fadeInUp 0.8s ease-out; -} - -.platform-hero-title { - font-weight: 500; - font-size: 42px; - color: var(--text-primary); - line-height: 1.2; - margin: 0; - animation: fadeInUp 0.8s ease-out 0.1s both; -} - -.platform-hero-subtitle { - font-weight: 500; - font-size: 24px; - color: var(--text-primary); - line-height: 1.3; - margin: 0; - animation: fadeInUp 0.8s ease-out 0.2s both; -} - -.platform-hero-tagline { - font-weight: 500; - font-size: 24px; - color: var(--text-primary); - line-height: 1.3; - margin: 0; - animation: fadeInUp 0.8s ease-out 0.3s both; -} - -.platform-hero-actions { - display: flex; + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; - margin-top: 12px; - animation: fadeInUp 0.8s ease-out 0.4s both; } -.platform-btn-primary { - display: flex; - align-items: center; - justify-content: center; - width: 280px; - height: 48px; - background: var(--gradient-primary); - border: 1px solid var(--border-color); - border-radius: var(--radius-lg); - font-weight: 500; - font-size: 20px; - color: #ffffff; - text-decoration: none; - letter-spacing: 1.08px; - cursor: pointer; - transition: all 0.3s ease; - box-shadow: 0 4px 12px rgba(73, 118, 113, 0.3); - - &:hover { - transform: translateY(-2px); - box-shadow: 0 6px 16px rgba(73, 118, 113, 0.4); - } - - &:active { - transform: translateY(0px); - box-shadow: 0 2px 8px rgba(73, 118, 113, 0.3); - } +.home-empty { + padding-block: 48px; } - -.platform-btn-secondary { - display: flex; - align-items: center; - justify-content: center; - gap: 9px; - width: 220px; - height: 48px; - background: var(--bg-secondary); - border: 1px solid var(--border-color); - border-radius: var(--radius-lg); - font-weight: 500; - font-size: 20px; - color: var(--text-primary); - letter-spacing: 1.08px; - cursor: pointer; - transition: all 0.3s ease; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - - svg { - width: 11px; - height: 16px; - transition: transform 0.3s ease; - } - - &:hover { - background: #ffffff; - transform: translateY(-2px); - box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15); - - svg { - transform: translateX(3px); - } - } - - &:active { - transform: translateY(0px); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - } -} - -// Loading & Error States -.platform-loading, -.platform-error { - text-align: center; - padding: 60px 20px; - max-width: 1200px; - margin: 0 auto; -} - -.platform-spinner { - width: 50px; - height: 50px; - border: 4px solid #f3f3f3; - border-top: 4px solid var(--primary-color); - border-radius: 50%; - animation: spin 1s linear infinite; - margin: 0 auto 20px; -} - -.platform-error { - button { - margin-top: 20px; - padding: 12px 28px; - background: var(--primary-color); - color: white; - border: none; - border-radius: var(--radius-lg); - cursor: pointer; - font-size: 1.1rem; - font-weight: 500; - transition: all 0.3s ease; - - &:hover { - background: var(--primary-hover); - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(73, 118, 113, 0.3); - } - } -} - -// Categories Section -.platform-categories { - max-width: 1440px; - margin: 50px auto; - padding: 0 56px; -} - -.platform-categories-title { - font-size: 2.5rem; - font-weight: 600; - margin-bottom: 40px; - color: var(--text-primary); -} - -.platform-empty-categories { - text-align: center; - padding: 80px 20px; - background: white; - border-radius: 16px; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); - - .platform-empty-icon { - font-size: 4rem; - margin-bottom: 20px; - opacity: 0.5; - } - - h3 { - font-size: 1.8rem; - color: var(--text-primary); - margin: 0 0 12px 0; - font-weight: 600; - } - - p { - color: var(--text-secondary); - font-size: 1.1rem; - margin: 0; - } -} - -.platform-categories-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 30px; - animation: fadeIn 0.6s ease-in 0.3s both; - width: 100%; -} - -.platform-category-card { - width: 100%; - display: flex; - flex-direction: column; - text-decoration: none; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - - &:hover { - transform: translateY(-4px); - - .platform-category-image { - box-shadow: 0 6px 8px 0 rgba(0, 0, 0, 0.2); - } - - .platform-category-info { - box-shadow: 0 6px 8px 0 rgba(0, 0, 0, 0.2); - } - } -} - -.platform-category-image { - width: 100%; - aspect-ratio: 4 / 3; - border: 1px solid var(--border-color); - border-radius: var(--radius-lg) var(--radius-lg) 0 0; - box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.15); - overflow: hidden; - display: flex; - align-items: center; - justify-content: center; - background: var(--bg-secondary); - position: relative; - - img { - width: 100%; - height: 100%; - object-fit: cover; - transition: transform 0.3s ease; - } - - &:hover img { - transform: scale(1.05); - } -} - -.platform-category-fallback { - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - font-size: 5rem; - font-weight: 700; - color: var(--primary-color); - background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--bg-tertiary) 100%); -} - -.platform-category-info { - width: 100%; - border: 1px solid var(--border-color); - border-top: none; - border-radius: 0 0 var(--radius-lg) var(--radius-lg); - padding: 12px 16px; - box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.15); - background: #f5f3f9; - display: flex; - flex-direction: column; - justify-content: center; - gap: 2px; - transition: background 0.3s ease; -} - -.platform-category-name { - font-weight: 600; - font-size: clamp(14px, 1.4vw, 18px); - color: var(--text-primary); - margin: 0; - line-height: 1.3; - display: -webkit-box; - line-clamp: 2; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - text-overflow: ellipsis; - min-height: calc(2 * 1.3em); -} - -.platform-category-count { - font-weight: 600; - font-size: clamp(11px, 1vw, 13px); - color: var(--text-secondary); - margin: 0; - line-height: 1.2; -} - -// Wide category card (spans 2 columns) -.platform-category-card--wide { - grid-column: span 2; - - .platform-category-image { - aspect-ratio: 8 / 3; - - img { - object-fit: cover; - } - } -} - -// Responsive Design -@media (max-width: 1200px) { - .platform-hero { - height: 380px; - } - - .platform-hero-overlay { - padding: 0 40px; - } - - .platform-hero-title { - font-size: 38px; - } - - .platform-hero-subtitle, - .platform-hero-tagline { - font-size: 22px; - } - - .platform-categories { - padding: 0 40px; - } - - .platform-categories-grid { - grid-template-columns: repeat(3, 1fr); - gap: 24px; - } -} - -@media (max-width: 992px) { - .platform-hero { - height: 340px; - } - - .platform-hero-overlay { - padding: 0 32px; - } - - .platform-hero-title { - font-size: 34px; - } - - .platform-hero-subtitle, - .platform-hero-tagline { - font-size: 20px; - } - - .platform-btn-primary, - .platform-btn-secondary { - height: 44px; - font-size: 18px; - } - - .platform-btn-primary { - width: 240px; - } - - .platform-btn-secondary { - width: 200px; - } - - .platform-categories { - padding: 0 32px; - } - - .platform-categories-grid { - grid-template-columns: repeat(3, 1fr); - gap: 20px; - } -} - -@media (max-width: 768px) { - .platform-hero { - height: 320px; - background-position: right center; - } - - .platform-hero-overlay { - padding: 0 20px; - background: linear-gradient( - to bottom, - rgba(255, 255, 255, 0.45) 0%, - rgba(255, 255, 255, 0.15) 100% - ); - } - - .platform-hero-title { - font-size: 28px; - } - - .platform-hero-subtitle, - .platform-hero-tagline { - font-size: 17px; - } - - .platform-hero-actions { - flex-direction: row; - gap: 10px; - width: 100%; - } - - .platform-btn-primary, - .platform-btn-secondary { - flex: 1; - min-width: 0; - max-width: 180px; - height: 40px; - font-size: 14px; - letter-spacing: 0.5px; - } - - .platform-categories { - margin: 40px auto; - padding: 0 20px; - } - - .platform-categories-title { - font-size: 2rem; - margin-bottom: 30px; - } - - .platform-categories-grid { - grid-template-columns: repeat(2, 1fr); - gap: 16px; - } - - .platform-category-info { - padding: 10px 12px; - } -} - -@media (max-width: 480px) { - .platform-hero { - height: 280px; - } - - .platform-hero-title { - font-size: 24px; - } - - .platform-hero-subtitle, - .platform-hero-tagline { - font-size: 15px; - } - - .platform-hero-actions { - gap: 10px; - } - - .platform-btn-primary, - .platform-btn-secondary { - height: 38px; - font-size: 13px; - max-width: 160px; - } - - .platform-categories { - padding: 0 16px; - } - - .platform-categories-grid { - grid-template-columns: repeat(2, 1fr); - gap: 12px; - } - - .platform-category-info { - padding: 8px 10px; - } - - .platform-category-card:hover { - transform: translateY(-2px); - } -} - -// Skeleton loading cards -.skeleton-card { - pointer-events: none; -} - -.skeleton-image { - background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); - background-size: 200% 100%; - animation: shimmer 1.5s infinite; -} - -.skeleton-line { - border-radius: 6px; - background: linear-gradient(90deg, #e8e8e8 25%, #d8d8d8 50%, #e8e8e8 75%); - background-size: 200% 100%; - animation: shimmer 1.5s infinite; -} - -@keyframes shimmer { - 0% { background-position: 200% 0; } - 100% { background-position: -200% 0; } -} - diff --git a/src/app/pages/home/home.component.ts b/src/app/pages/home/home.component.ts index 72db0bf..e881464 100644 --- a/src/app/pages/home/home.component.ts +++ b/src/app/pages/home/home.component.ts @@ -4,11 +4,13 @@ import { DynamicPageLayoutComponent } from '../../layouts/containers/dynamic-pag import { PageRenderModel } from '../../dynamic-renderer/page-renderer/page-renderer.model'; import { WebsiteRuntimeFacade } from '../../facades/website/website-runtime.facade'; import { TranslatePipe } from '../../i18n/translate.pipe'; +import { SkeletonComponent } from '../../shared/ui/skeleton/skeleton.component'; +import { EmptyStateComponent } from '../../shared/ui/empty-state/empty-state.component'; @Component({ selector: 'app-home', standalone: true, - imports: [DynamicPageLayoutComponent, TranslatePipe], + imports: [DynamicPageLayoutComponent, TranslatePipe, SkeletonComponent, EmptyStateComponent], templateUrl: './home.component.html', styleUrls: ['./home.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush @@ -19,6 +21,7 @@ export class HomeComponent implements OnInit { private readonly websiteRuntime: WebsiteRuntimeFacade ) {} + readonly skeletonCards = [0, 1, 2, 3]; loading = signal(true); error = signal(null); readonly pageModel = signal(null);