initial mobile support

This commit is contained in:
lowcarbdev
2025-11-22 10:29:41 -07:00
parent 946a31a1a6
commit 92092d2544
2 changed files with 72 additions and 5 deletions
+43
View File
@@ -40,3 +40,46 @@
.read-the-docs { .read-the-docs {
color: #888; color: #888;
} }
/* Mobile-friendly conversation sidebar */
.conversation-sidebar {
width: 380px;
min-width: 380px;
max-width: 380px;
flex-shrink: 0;
transition: transform 0.3s ease-in-out;
}
/* Mobile styles - screens smaller than 768px (Bootstrap md breakpoint) */
@media (max-width: 767.98px) {
.conversation-sidebar {
position: absolute;
top: 0;
left: 0;
width: 100%;
max-width: 100%;
min-width: 100%;
height: 100%;
z-index: 1000;
transform: translateX(-100%);
}
.conversation-sidebar.show {
transform: translateX(0);
}
.message-thread-container {
width: 100%;
}
}
/* Tablet and desktop - show both sidebar and content */
@media (min-width: 768px) {
.conversation-sidebar {
transform: translateX(0) !important;
}
.mobile-back-button {
display: none !important;
}
}
+29 -5
View File
@@ -29,6 +29,9 @@ function App() {
const [showPasswordModal, setShowPasswordModal] = useState(false) const [showPasswordModal, setShowPasswordModal] = useState(false)
const [searchFilter, setSearchFilter] = useState('') const [searchFilter, setSearchFilter] = useState('')
// Mobile sidebar state
const [showSidebar, setShowSidebar] = useState(true)
// Search state (persisted across tab switches) // Search state (persisted across tab switches)
const [searchQuery, setSearchQuery] = useState('') const [searchQuery, setSearchQuery] = useState('')
const [searchResults, setSearchResults] = useState([]) const [searchResults, setSearchResults] = useState([])
@@ -54,7 +57,7 @@ function App() {
fetchConversations() fetchConversations()
}, [startDate, endDate]) }, [startDate, endDate])
// Sync selected conversation from URL // Sync selected conversation from URL and manage sidebar visibility
useEffect(() => { useEffect(() => {
const match = location.pathname.match(/^\/conversation\/(.+)$/) const match = location.pathname.match(/^\/conversation\/(.+)$/)
if (match) { if (match) {
@@ -67,8 +70,11 @@ function App() {
// If conversation not found in list, create a minimal conversation object // If conversation not found in list, create a minimal conversation object
setSelectedConversation({ address, contact_name: address, type: 'message' }) setSelectedConversation({ address, contact_name: address, type: 'message' })
} }
} else if (location.pathname === '/' || location.pathname === '/conversations') { } else {
// Not viewing a specific conversation
setSelectedConversation(null) setSelectedConversation(null)
// Show sidebar when navigating to any non-conversation view
setShowSidebar(true)
} }
}, [location.pathname, conversations]) }, [location.pathname, conversations])
@@ -109,6 +115,8 @@ function App() {
const handleSelectConversation = (conversation) => { const handleSelectConversation = (conversation) => {
if (conversation) { if (conversation) {
navigate(`/conversation/${encodeURIComponent(conversation.address)}`) navigate(`/conversation/${encodeURIComponent(conversation.address)}`)
// Hide sidebar on mobile when conversation is selected
setShowSidebar(false)
} }
} }
@@ -262,11 +270,13 @@ function App() {
</div> </div>
{/* Main Content */} {/* Main Content */}
<div className="flex-fill d-flex overflow-hidden gap-2 p-2"> <div className="flex-fill d-flex overflow-hidden gap-2 p-2 position-relative">
{activeView === 'conversations' ? ( {activeView === 'conversations' ? (
<> <>
{/* Conversation List */} {/* Conversation List */}
<div style={{width: '380px', minWidth: '380px', maxWidth: '380px', flexShrink: 0}} className="bg-white rounded-3 shadow overflow-hidden border"> <div
className={`conversation-sidebar bg-white rounded-3 shadow overflow-hidden border ${showSidebar ? 'show' : ''}`}
>
<div className="bg-light border-bottom p-2"> <div className="bg-light border-bottom p-2">
<h2 className="h5 mb-2 d-flex align-items-center gap-2"> <h2 className="h5 mb-2 d-flex align-items-center gap-2">
<svg style={{width: '1.25rem', height: '1.25rem'}} className="text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg style={{width: '1.25rem', height: '1.25rem'}} className="text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -298,7 +308,21 @@ function App() {
</div> </div>
{/* Message Thread */} {/* Message Thread */}
<div className="flex-fill bg-white rounded-3 shadow overflow-hidden border" style={{minWidth: 0}}> <div className="flex-fill bg-white rounded-3 shadow overflow-hidden border message-thread-container" style={{minWidth: 0}}>
{/* Mobile back button */}
{selectedConversation && (
<div className="mobile-back-button bg-light border-bottom p-2 d-md-none">
<button
className="btn btn-sm btn-outline-primary"
onClick={() => setShowSidebar(true)}
>
<svg style={{width: '1rem', height: '1rem'}} fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
Back to conversations
</button>
</div>
)}
<MessageThread <MessageThread
conversation={selectedConversation} conversation={selectedConversation}
startDate={startDate} startDate={startDate}