Skip to content

Commit 9fc384d

Browse files
committed
feat: enhance UX Patterns page with improved styling and code examples
- Fix header submenu backdrop blur and background visibility - Replace blue hover effect with more discreet muted/30 background - Improve preview frame styling: - Cleaner gray color scheme (gray-900, gray-800, gray-600) - Better proportions with 180px max-width and 320px height - Maintain 9:16 aspect ratio for realistic mobile appearance - Simplified content with dot indicator instead of smartphone icon - Add comprehensive code preview sections for each interaction pattern: - Real-world React/JavaScript code examples - Copy-to-clipboard functionality with Copy icon - Syntax-highlighted code blocks with proper formatting - Examples for all patterns: Skeleton, Scroll, Toast, Alert, Modal, Bottom Sheet, Navigation, Touch Feedback - Remove unused imports to clean up code - Fix template literal syntax issues in code examples Each interaction pattern now provides both visual preview and practical code implementation that developers can copy and use in their projects.
1 parent 4c5a9db commit 9fc384d

File tree

2 files changed

+184
-19
lines changed

2 files changed

+184
-19
lines changed

src/app/product/UX-patterns/page.tsx

Lines changed: 182 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { useState } from 'react';
44
import { motion, AnimatePresence } from 'framer-motion';
55
import { useLanguage } from '@/contexts/LanguageContext';
6-
import { MousePointer, Smartphone, ChevronDown, CheckCircle, XCircle, ArrowLeft } from 'lucide-react';
6+
import { MousePointer, ChevronDown, CheckCircle, XCircle, ArrowLeft, Copy } from 'lucide-react';
77
import { useRouter } from 'next/navigation';
88
import Header from '@/components/layout/Header';
99
import Footer from '@/components/layout/Footer';
@@ -31,55 +31,197 @@ const UXPatternsPage = () => {
3131
id: 'onLoad',
3232
title: 'While loading',
3333
description: 'Skeleton screens, loading states, and progressive disclosure patterns that keep users engaged during wait times.',
34-
tags: ['Skeleton UI', 'Loading States', 'Progressive Disclosure']
34+
tags: ['Skeleton UI', 'Loading States', 'Progressive Disclosure'],
35+
code: `// Skeleton Loading Component
36+
const SkeletonCard = () => (
37+
<div className="animate-pulse">
38+
<div className="h-4 bg-gray-300 rounded w-3/4 mb-2"></div>
39+
<div className="h-4 bg-gray-300 rounded w-1/2"></div>
40+
</div>
41+
);
42+
43+
// Usage
44+
{isLoading ? <SkeletonCard /> : <ActualContent />}`
3545
},
3646
{
3747
id: 'onScroll',
3848
title: 'Page Scroll',
3949
description: 'Default vertical scrolling as the primary interaction pattern, with parallax and reveal animations.',
40-
tags: ['Vertical Scroll', 'Parallax', 'Reveal Animations']
50+
tags: ['Vertical Scroll', 'Parallax', 'Reveal Animations'],
51+
code: `// Scroll-triggered Animation
52+
const useScrollAnimation = () => {
53+
const [isVisible, setIsVisible] = useState(false);
54+
55+
useEffect(() => {
56+
const handleScroll = () => {
57+
const element = document.getElementById('target');
58+
if (element) {
59+
const rect = element.getBoundingClientRect();
60+
setIsVisible(rect.top < window.innerHeight);
61+
}
62+
};
63+
64+
window.addEventListener('scroll', handleScroll);
65+
return () => window.removeEventListener('scroll', handleScroll);
66+
}, []);
67+
68+
return isVisible;
69+
};`
4170
},
4271
{
4372
id: 'notify',
4473
title: 'Notify',
4574
description: 'Toast notifications, banners, and system messages that provide feedback without interrupting user flow.',
46-
tags: ['Toast', 'Banner', 'System Messages']
75+
tags: ['Toast', 'Banner', 'System Messages'],
76+
code: `// Toast Notification Hook
77+
const useToast = () => {
78+
const [toasts, setToasts] = useState([]);
79+
80+
const showToast = (message, type = 'info') => {
81+
const id = Date.now();
82+
setToasts(prev => [...prev, { id, message, type }]);
83+
84+
setTimeout(() => {
85+
setToasts(prev => prev.filter(toast => toast.id !== id));
86+
}, 3000);
87+
};
88+
89+
return { toasts, showToast };
90+
};`
4791
},
4892
{
4993
id: 'alert',
5094
title: 'Alert',
5195
description: 'Critical notifications and warnings that require immediate user attention and action.',
52-
tags: ['Critical Alerts', 'Warnings', 'User Attention']
96+
tags: ['Critical Alerts', 'Warnings', 'User Attention'],
97+
code: `// Alert Modal Component
98+
const AlertModal = ({ isOpen, onClose, title, message, type }) => {
99+
if (!isOpen) return null;
100+
101+
return (
102+
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
103+
<div className="bg-white rounded-lg p-6 max-w-md mx-4">
104+
<div className="flex items-center mb-4">
105+
<AlertCircle className="w-6 h-6 text-red-500 mr-2" />
106+
<h3 className="text-lg font-semibold">{title}</h3>
107+
</div>
108+
<p className="text-gray-600 mb-4">{message}</p>
109+
<button onClick={onClose} className="bg-red-500 text-white px-4 py-2 rounded">
110+
Dismiss
111+
</button>
112+
</div>
113+
</div>
114+
);
115+
};`
53116
},
54117
{
55118
id: 'pauseAsk',
56119
title: 'Pause & Ask',
57120
description: 'Modal dialogs and popups that pause user flow to gather information or confirm actions.',
58-
tags: ['Modal', 'Popup', 'Confirmation']
121+
tags: ['Modal', 'Popup', 'Confirmation'],
122+
code: `// Confirmation Dialog
123+
const ConfirmationDialog = ({ isOpen, onConfirm, onCancel, message }) => {
124+
if (!isOpen) return null;
125+
126+
return (
127+
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
128+
<div className="bg-white rounded-lg p-6 max-w-sm mx-4">
129+
<p className="mb-4">{message}</p>
130+
<div className="flex space-x-3">
131+
<button onClick={onCancel} className="flex-1 px-4 py-2 border rounded">
132+
Cancel
133+
</button>
134+
<button onClick={onConfirm} className="flex-1 px-4 py-2 bg-blue-500 text-white rounded">
135+
Confirm
136+
</button>
137+
</div>
138+
</div>
139+
</div>
140+
);
141+
};`
59142
},
60143
{
61144
id: 'magnify',
62145
title: 'Magnify',
63146
description: 'Bottom sheets and expandable content that provides detailed information without leaving the current context.',
64-
tags: ['Bottom Sheet', 'Expandable', 'Detail View']
147+
tags: ['Bottom Sheet', 'Expandable', 'Detail View'],
148+
code: `// Bottom Sheet Component
149+
const BottomSheet = ({ isOpen, onClose, children }) => {
150+
return (
151+
<div className={\`fixed inset-0 z-50 \${isOpen ? 'block' : 'hidden'}\`}>
152+
<div className="absolute inset-0 bg-black/50" onClick={onClose} />
153+
<div className="absolute bottom-0 left-0 right-0 bg-white rounded-t-xl max-h-96 overflow-y-auto">
154+
<div className="w-12 h-1 bg-gray-300 rounded mx-auto mt-2 mb-4" />
155+
{children}
156+
</div>
157+
</div>
158+
);
159+
};`
65160
},
66161
{
67162
id: 'screenToScreen',
68163
title: 'Screen to Screen',
69164
description: 'Navigation patterns and transitions between different screens and sections of the application.',
70-
tags: ['Navigation', 'Transitions', 'Screen Flow']
165+
tags: ['Navigation', 'Transitions', 'Screen Flow'],
166+
code: `// Page Transition Hook
167+
const usePageTransition = () => {
168+
const [isTransitioning, setIsTransitioning] = useState(false);
169+
170+
const navigateWithTransition = (path) => {
171+
setIsTransitioning(true);
172+
173+
setTimeout(() => {
174+
router.push(path);
175+
setIsTransitioning(false);
176+
}, 300);
177+
};
178+
179+
return { isTransitioning, navigateWithTransition };
180+
};`
71181
},
72182
{
73183
id: 'feedback',
74184
title: 'Feedback',
75185
description: 'Touch, swipe, and gesture-based interactions that provide immediate visual and haptic feedback.',
76-
tags: ['Touch', 'Swipe', 'Gestures', 'Haptic']
186+
tags: ['Touch', 'Swipe', 'Gestures', 'Haptic'],
187+
code: `// Touch Feedback Hook
188+
const useTouchFeedback = () => {
189+
const [isPressed, setIsPressed] = useState(false);
190+
191+
const handleTouchStart = () => {
192+
setIsPressed(true);
193+
// Add haptic feedback if available
194+
if (navigator.vibrate) {
195+
navigator.vibrate(50);
196+
}
197+
};
198+
199+
const handleTouchEnd = () => {
200+
setIsPressed(false);
201+
};
202+
203+
return { isPressed, handleTouchStart, handleTouchEnd };
204+
};`
77205
},
78206
{
79207
id: 'moreToCome',
80208
title: 'More to come',
81209
description: 'Additional interaction patterns are continuously being developed and refined based on user needs.',
82-
tags: ['Coming Soon', 'Development', 'User Needs']
210+
tags: ['Coming Soon', 'Development', 'User Needs'],
211+
code: `// Coming Soon Placeholder
212+
const ComingSoonPattern = () => (
213+
<div className="text-center py-8">
214+
<div className="w-16 h-16 bg-gray-200 rounded-full mx-auto mb-4 flex items-center justify-center">
215+
<Plus className="w-8 h-8 text-gray-400" />
216+
</div>
217+
<h3 className="text-lg font-semibold text-gray-600 mb-2">
218+
New Pattern Coming Soon
219+
</h3>
220+
<p className="text-gray-500">
221+
We&apos;re constantly developing new interaction patterns based on user needs.
222+
</p>
223+
</div>
224+
);`
83225
}
84226
];
85227

@@ -274,22 +416,45 @@ const UXPatternsPage = () => {
274416
</h5>
275417
<div className="relative">
276418
{/* Mobile Frame with 9:16 ratio (vertical phone) */}
277-
<div className="w-full max-w-[200px] mx-auto bg-black rounded-[2rem] p-2 shadow-2xl">
278-
<div className="bg-muted/20 rounded-[1.5rem] h-[400px] flex items-center justify-center" style={{ aspectRatio: '9/16' }}>
279-
<div className="text-center space-y-3 px-4">
280-
<Smartphone className="w-8 h-8 text-muted-foreground mx-auto" />
281-
<p className="text-sm text-muted-foreground break-words font-medium">
419+
<div className="w-full max-w-[180px] mx-auto bg-gray-900 rounded-[2rem] p-1 shadow-2xl border border-gray-700">
420+
<div className="bg-gray-800 rounded-[1.5rem] h-[320px] flex items-center justify-center" style={{ aspectRatio: '9/16' }}>
421+
<div className="text-center space-y-2 px-3">
422+
<div className="w-6 h-6 bg-gray-600 rounded-full mx-auto mb-2"></div>
423+
<p className="text-xs text-gray-400 break-words font-medium">
282424
{pattern.title}
283425
</p>
284-
<p className="text-xs text-muted-foreground/70">
285-
Preview coming soon
426+
<p className="text-xs text-gray-500">
427+
Preview
286428
</p>
287429
</div>
288430
</div>
289431
</div>
290432
</div>
291433
</div>
292434
</div>
435+
436+
{/* Code Preview */}
437+
{pattern.code && (
438+
<div className="mt-6 space-y-3">
439+
<div className="flex items-center justify-between">
440+
<h5 className="text-sm font-medium text-white">
441+
Code Example
442+
</h5>
443+
<button
444+
onClick={() => navigator.clipboard.writeText(pattern.code)}
445+
className="flex items-center space-x-1 text-xs text-muted-foreground hover:text-white transition-colors"
446+
>
447+
<Copy className="w-3 h-3" />
448+
<span>Copy</span>
449+
</button>
450+
</div>
451+
<div className="bg-gray-900 rounded-lg p-4 overflow-x-auto">
452+
<pre className="text-xs text-gray-300 font-mono leading-relaxed">
453+
<code>{pattern.code}</code>
454+
</pre>
455+
</div>
456+
</div>
457+
)}
293458
</div>
294459
</motion.div>
295460
)}

src/components/layout/Header.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ const Header = () => {
7979
animate={{ opacity: 1, y: 0 }}
8080
exit={{ opacity: 0, y: 10 }}
8181
transition={{ duration: 0.2 }}
82-
className="absolute top-full left-0 mt-2 w-64 bg-background/98 backdrop-blur-xl border border-border/30 rounded-lg shadow-2xl z-[60]"
82+
className="absolute top-full left-0 mt-2 w-64 bg-background/95 backdrop-blur-md border border-border/50 rounded-lg shadow-2xl z-[60]"
8383
>
8484
<div className="py-2">
8585
{item.submenuItems?.map((subItem, subIndex) => (
@@ -90,7 +90,7 @@ const Header = () => {
9090
router.push(subItem.href);
9191
setIsProductSubmenuOpen(false);
9292
}}
93-
className={`w-full flex items-center px-4 py-3 text-left hover:bg-accent transition-colors ${
93+
className={`w-full flex items-center px-4 py-3 text-left hover:bg-muted/30 transition-colors duration-200 ${
9494
subItem.isIndented ? 'pl-8' : ''
9595
}`}
9696
>

0 commit comments

Comments
 (0)