feat: replace mobile agent card slider with horizontal swipe carousel and improve messaging header responsiveness
This commit is contained in:
@@ -33,14 +33,14 @@ export function ConnectionCard({
|
||||
const isPlaceholder = !avatar || avatar === placeholder;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4 py-4">
|
||||
<div className="flex flex-row items-center gap-3 sm:gap-4 py-4">
|
||||
{/* Avatar */}
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-[80px] h-[80px] rounded-full overflow-hidden relative bg-[#e8e8e8]">
|
||||
<div className="w-[56px] h-[56px] sm:w-[80px] sm:h-[80px] rounded-full overflow-hidden relative bg-[#e8e8e8]">
|
||||
{/* Shimmer while loading, initials only on error */}
|
||||
{avatarError || isPlaceholder ? (
|
||||
<div className="absolute inset-0 rounded-full bg-[#c4d9d4] flex items-center justify-center">
|
||||
<span className="font-bold text-[#00293d] text-[32px]">{name?.[0]?.toUpperCase() || '?'}</span>
|
||||
<span className="font-bold text-[#00293d] text-[22px] sm:text-[32px]">{name?.[0]?.toUpperCase() || '?'}</span>
|
||||
</div>
|
||||
) : !avatarLoaded ? (
|
||||
<div className="absolute inset-0 rounded-full shimmer-loading" />
|
||||
@@ -58,19 +58,15 @@ export function ConnectionCard({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
{/* Content + Message button (stacks on mobile, inline on desktop) */}
|
||||
<div className="flex-1 min-w-0 flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
||||
<div className="flex-1 min-w-0">
|
||||
{/* Name */}
|
||||
<h3 className="font-serif font-bold text-[14px] leading-[19px] text-[#00293D] mb-1">
|
||||
<h3 className="font-serif font-bold text-[14px] leading-[19px] text-[#00293D] mb-1 truncate">
|
||||
{name}
|
||||
</h3>
|
||||
|
||||
{/* Email */}
|
||||
<p className="font-serif font-normal text-[13px] leading-[18px] text-[#00293D]/70 mb-1">
|
||||
<p className="font-serif font-normal text-[13px] leading-[18px] text-[#00293D]/70 mb-1 truncate">
|
||||
{email}
|
||||
</p>
|
||||
|
||||
{/* Connected date */}
|
||||
{connectedAt && (
|
||||
<p className="font-serif font-normal text-[12px] text-[#00293D]/50">
|
||||
Connected on {formatDate(connectedAt)}
|
||||
@@ -78,7 +74,7 @@ export function ConnectionCard({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
{/* Action Button */}
|
||||
<div className="flex items-center gap-3 flex-shrink-0">
|
||||
<button
|
||||
onClick={() => onMessage?.(id)}
|
||||
@@ -94,5 +90,6 @@ export function ConnectionCard({
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -106,18 +106,30 @@ export function FeaturesSection({ content }: { content?: FeaturesContent }) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Mobile Agent Cards - Tab style with dots */}
|
||||
{/* Mobile Agent Cards - Horizontal swipe carousel */}
|
||||
{agents.length > 0 && (
|
||||
<div className="lg:hidden">
|
||||
<div className="flex justify-center">
|
||||
<AgentCard agent={agents[activeCard]} className="shadow-lg" />
|
||||
<div
|
||||
className="flex gap-4 overflow-x-auto snap-x snap-mandatory scroll-smooth pb-2 -mx-4 px-4"
|
||||
onScroll={(e) => {
|
||||
const el = e.currentTarget;
|
||||
const cardWidth = el.children[0]?.clientWidth || 254;
|
||||
const gap = 16;
|
||||
const idx = Math.round(el.scrollLeft / (cardWidth + gap));
|
||||
if (idx !== activeCard) setActiveCard(idx);
|
||||
}}
|
||||
>
|
||||
{agents.map((agent, index) => (
|
||||
<div key={index} className="snap-center flex-shrink-0">
|
||||
<AgentCard agent={agent} className="shadow-lg" />
|
||||
</div>
|
||||
{/* Dot indicators */}
|
||||
))}
|
||||
</div>
|
||||
{/* Dot indicators (visual only — swipe to change) */}
|
||||
<div className="flex justify-center gap-2 mt-4">
|
||||
{agents.map((_, index) => (
|
||||
<button
|
||||
<span
|
||||
key={index}
|
||||
onClick={() => setActiveCard(index)}
|
||||
className={`rounded-full transition-all ${
|
||||
index === activeCard
|
||||
? 'w-[10px] h-[10px] bg-[#00293d]'
|
||||
|
||||
@@ -351,8 +351,7 @@ export function MessageInput({ onSend, onSendGif, onSendFile, onTypingStart, onT
|
||||
{showGifPicker && (
|
||||
<div
|
||||
ref={gifPickerRef}
|
||||
className="absolute bottom-full left-0 mb-2 z-50 bg-white border border-[#00293d]/10 rounded-[15px] shadow-lg overflow-hidden"
|
||||
style={{ width: '360px', height: '420px' }}
|
||||
className="absolute bottom-full left-0 mb-2 z-50 bg-white border border-[#00293d]/10 rounded-[15px] shadow-lg overflow-hidden w-[min(360px,calc(100vw-32px))] h-[420px]"
|
||||
>
|
||||
<div className="p-3 border-b border-[#00293d]/10">
|
||||
<input
|
||||
@@ -368,7 +367,7 @@ export function MessageInput({ onSend, onSendGif, onSendFile, onTypingStart, onT
|
||||
<Grid
|
||||
key={gifSearchQuery}
|
||||
fetchGifs={fetchGifs}
|
||||
width={356}
|
||||
width={typeof window !== 'undefined' ? Math.min(356, window.innerWidth - 40) : 356}
|
||||
columns={2}
|
||||
gutter={6}
|
||||
noLink
|
||||
|
||||
@@ -665,7 +665,7 @@ export function MessagingPage({ initialConversationId, initialAgentProfileId }:
|
||||
|
||||
<div className="border border-[#00293d]/10 rounded-[20px] bg-white overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="flex items-center gap-4 p-4 border-b border-[#00293d]/10">
|
||||
<div className="flex flex-wrap md:flex-nowrap items-center gap-3 md:gap-4 p-4 border-b border-[#00293d]/10">
|
||||
<h1 className="font-fractul font-bold text-[18px] leading-[22px] text-[#00293D]">
|
||||
Messaging
|
||||
</h1>
|
||||
@@ -678,8 +678,8 @@ export function MessagingPage({ initialConversationId, initialAgentProfileId }:
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Search bar */}
|
||||
<div className="flex-1 max-w-[600px]">
|
||||
{/* Search bar — full width below on mobile, inline on desktop */}
|
||||
<div className="order-3 md:order-none w-full md:w-auto md:flex-1 md:max-w-[600px]">
|
||||
<div className="flex items-center gap-2 border border-[#00293d]/10 rounded-[15px] px-4 py-2">
|
||||
<Image
|
||||
src="/assets/icons/search-icon.svg"
|
||||
@@ -692,7 +692,7 @@ export function MessagingPage({ initialConversationId, initialAgentProfileId }:
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder="Search Message"
|
||||
className="flex-1 font-serif font-normal text-[18px] leading-[24px] text-[#00293D] placeholder-[#00293D]/50 focus:outline-none"
|
||||
className="flex-1 min-w-0 font-serif font-normal text-[14px] md:text-[18px] leading-[24px] text-[#00293D] placeholder-[#00293D]/50 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -76,7 +76,7 @@ export function FilterModal({ isOpen, onClose, filters, filterFields, onToggleFi
|
||||
</svg>
|
||||
</button>
|
||||
{expandedSections[field.slug] && (
|
||||
<div className={`grid ${field.options.length > 6 ? 'grid-cols-3' : 'grid-cols-3'} gap-x-6 gap-y-3`}>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-x-4 md:gap-x-6 gap-y-3">
|
||||
{field.options.map((option) => (
|
||||
<label key={option.value} className="flex items-start gap-2 cursor-pointer">
|
||||
<input
|
||||
|
||||
@@ -278,13 +278,13 @@ export function NotificationsForm({ onSave }: NotificationsFormProps) {
|
||||
</p>
|
||||
|
||||
{/* Frequency Tabs */}
|
||||
<div className="inline-flex items-center border border-[#00293D]/10 rounded-[7px] h-[49px] px-2">
|
||||
<div className="flex items-center border border-[#00293D]/10 rounded-[7px] h-[49px] px-2 w-full md:w-fit">
|
||||
{frequencyOptions.map((option, index) => (
|
||||
<div key={option.value} className="flex items-center h-full">
|
||||
<div key={option.value} className="flex items-center h-full flex-1 md:flex-initial">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setDigestFrequency(option.value)}
|
||||
className={`px-5 py-1.5 text-[14px] font-fractul transition-colors rounded-[15px] ${
|
||||
className={`w-full md:w-auto px-3 md:px-5 py-1.5 text-[14px] font-fractul transition-colors rounded-[15px] ${
|
||||
digestFrequency === option.value
|
||||
? 'bg-[#e58625] text-[#00293D]'
|
||||
: 'text-[#00293D] hover:bg-[#00293D]/5'
|
||||
|
||||
Reference in New Issue
Block a user