From 20edc7f63a09c3eeee4c2c44ddd15a85c4055cef Mon Sep 17 00:00:00 2001 From: Dev Date: Tue, 20 Jan 2026 23:32:11 +0500 Subject: [PATCH] phase 9 done. ready to restyle --- .ai/BENTO_REFACTOR.md | 22 +++++++++++++ src/components/ui/BentoSkeleton.tsx | 28 +++++++++++++++++ src/styles/globals.css | 48 +++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 src/components/ui/BentoSkeleton.tsx diff --git a/.ai/BENTO_REFACTOR.md b/.ai/BENTO_REFACTOR.md index f51dac0..3fab39c 100644 --- a/.ai/BENTO_REFACTOR.md +++ b/.ai/BENTO_REFACTOR.md @@ -130,6 +130,7 @@ interface BentoCardProps { Этап 6: ██████████ 100% Этап 7: ██████████ 100% Этап 8: ██████████ 100% +Этап 9: ██████████ 100% ───────────────────── Общий: ██████████ 100% ``` @@ -193,6 +194,16 @@ interface BentoCardProps { | 7.3 | Controls в bento-стиле | `[x]` | Все кнопки: `rounded-xl bg-dark-800/50 hover:bg-dark-700 border border-dark-700/50` | | 7.4 | Z-Index = 50 | `[x]` | Подтверждено (выше контента, ниже модалок z-[60]) | +### Этап 9: Visual Mastery (Final) +> Премиум визуальная полировка + +| # | Задача | Статус | Заметки | +|---|--------|--------|---------| +| 9.1 | Background Noise | `[x]` | SVG fractalNoise, 3% opacity, mix-blend-mode: overlay, z-index: 0 | +| 9.2 | Spotlight Effect | `[x]` | `::after` radial-gradient на hover, opacity transition | +| 9.3 | BentoSkeleton | `[x]` | Компонент с animate-pulse, поддержка count prop | +| 9.4 | Glass Border | `[x]` | `box-shadow: inset 0 1px 0 0 rgba(255,255,255,0.05)` на base, 0.1 на hover | + ### Этап 8: Полировка > Финальные штрихи @@ -235,6 +246,17 @@ interface BentoCardProps { - ✅ **Profile.tsx**: 3 карточки → `bento-card` - ✅ **Info.tsx**: FAQ items, rules, privacy, offer → `bento-card` +### 2026-01-20 — Phase 9 Complete (Visual Mastery) +- ✅ **Background Noise:** SVG `fractalNoise` pattern, 3% opacity, `mix-blend-mode: overlay` +- ✅ **Spotlight Effect:** `::after` pseudo-element с `radial-gradient(circle at top, rgba(255,255,255,0.06), transparent 60%)` +- ✅ **BentoSkeleton Component:** `src/components/ui/BentoSkeleton.tsx` — `animate-pulse`, supports `count` prop +- ✅ **Glass Border:** `box-shadow: inset 0 1px 0 0 rgba(255,255,255,0.05)` (0.1 on hover) +- ✅ **Light Theme:** Warm spotlight `rgba(255,253,249,0.8)`, champagne glass borders + +**My Fixes (Inspector Review):** +- Fixed `z-index: 9999` → `z-index: 0` on noise overlay (was blocking modals!) +- Fixed BentoSkeleton — removed `bento-card` class to avoid entrance animation on skeleton + ### 2026-01-20 — Phase 8 Complete (Полировка) - ✅ **Stagger Animation:** `@keyframes bentoFadeIn` (fade-in + translateY(16px→0)) - ✅ **CSS Variable `--stagger`:** Для delay между карточками (50ms increments) diff --git a/src/components/ui/BentoSkeleton.tsx b/src/components/ui/BentoSkeleton.tsx new file mode 100644 index 0000000..d7e47a0 --- /dev/null +++ b/src/components/ui/BentoSkeleton.tsx @@ -0,0 +1,28 @@ +interface BentoSkeletonProps { + className?: string + count?: number +} + +export default function BentoSkeleton({ className = '', count = 1 }: BentoSkeletonProps) { + const baseClasses = `animate-pulse bg-dark-800/50 border border-dark-700/30 rounded-[var(--bento-radius,24px)] min-h-[160px] w-full ${className}` + + if (count > 1) { + return ( + <> + {Array.from({ length: count }).map((_, i) => ( +
+ ))} + + ) + } + + return ( +
+ ) +} diff --git a/src/styles/globals.css b/src/styles/globals.css index e548a1b..4f14a5d 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -153,6 +153,19 @@ overscroll-behavior-y: contain; /* iOS smooth scrolling */ -webkit-overflow-scrolling: touch; + position: relative; + } + + /* Global Noise Texture */ + body::before { + content: ""; + position: fixed; + inset: 0; + z-index: 0; + pointer-events: none; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); + opacity: 0.03; + mix-blend-mode: overlay; } /* Optimize main scrollable content */ @@ -370,9 +383,13 @@ border-radius: var(--bento-radius); padding: var(--bento-padding); transform: translateZ(0); + /* Glass Border - Inset Highlight */ + box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.05); /* Stagger animation support */ animation: bentoFadeIn 0.5s cubic-bezier(0.16, 1, 0.3, 1) both; animation-delay: calc(var(--stagger, 0) * 50ms); + position: relative; + overflow: hidden; } @media (min-width: 1024px) { @@ -396,6 +413,26 @@ .bento-card-hover:hover { @apply bg-dark-800/60 border-dark-600/50 shadow-lg; transform: translateY(-4px); + /* Intensify Glass Border & Add Top Spotlight */ + box-shadow: + inset 0 1px 0 0 rgba(255, 255, 255, 0.1), + 0 10px 40px -10px rgba(0,0,0,0.5); + } + + /* CSS Spotlight Effect via pseudo-element */ + .bento-card-hover::after { + content: ""; + position: absolute; + inset: 0; + background: radial-gradient(circle at top, rgba(255, 255, 255, 0.06), transparent 60%); + opacity: 0; + transition: opacity 0.3s ease; + pointer-events: none; + z-index: 10; + } + + .bento-card-hover:hover::after { + opacity: 1; } .bento-card-hover:active { @@ -439,6 +476,8 @@ .light .bento-card { @apply bg-white/90 border-champagne-300/50 shadow-sm; + /* Light Theme Glass Border */ + box-shadow: inset 0 1px 0 0 rgba(0, 0, 0, 0.03); } @media (min-width: 1024px) { @@ -450,6 +489,15 @@ .light .bento-card-hover:hover { @apply bg-white border-champagne-400/50 shadow-md; transform: translateY(-4px); + /* Intensify Light Theme Glass Border */ + box-shadow: + inset 0 1px 0 0 rgba(0, 0, 0, 0.06), + 0 10px 40px -10px rgba(160, 139, 94, 0.15); + } + + /* Adjust spotlight for light theme to be a warm glow */ + .light .bento-card-hover::after { + background: radial-gradient(circle at top, rgba(255, 253, 249, 0.8), transparent 70%); } .light .bento-card-glow:hover {