mirror of
https://github.com/dergigi/boris.git
synced 2025-12-18 15:14:20 +01:00
feat: reorganize bookmarks UI - add explore button and move refresh
- Move refresh button from top bar to end of bookmarks list - Show relative time of last fetch next to refresh button - Add 'Explore' button (fa-newspaper icon) to top bar that links to /explore - Track lastFetchTime in useBookmarksData hook - Better UX with explore more prominent and refresh less intrusive
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faChevronLeft, faBookmark, faSpinner, faList, faThLarge, faImage } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faChevronLeft, faBookmark, faSpinner, faList, faThLarge, faImage, faRotate } from '@fortawesome/free-solid-svg-icons'
|
||||
import { formatDistanceToNow } from 'date-fns'
|
||||
import { RelayPool } from 'applesauce-relay'
|
||||
import { Bookmark, IndividualBookmark } from '../types/bookmarks'
|
||||
import { BookmarkItem } from './BookmarkItem'
|
||||
@@ -22,6 +23,7 @@ interface BookmarkListProps {
|
||||
onOpenSettings: () => void
|
||||
onRefresh?: () => void
|
||||
isRefreshing?: boolean
|
||||
lastFetchTime?: number | null
|
||||
loading?: boolean
|
||||
relayPool: RelayPool | null
|
||||
settings?: UserSettings
|
||||
@@ -39,6 +41,7 @@ export const BookmarkList: React.FC<BookmarkListProps> = ({
|
||||
onOpenSettings,
|
||||
onRefresh,
|
||||
isRefreshing,
|
||||
lastFetchTime,
|
||||
loading = false,
|
||||
relayPool,
|
||||
settings
|
||||
@@ -102,8 +105,6 @@ export const BookmarkList: React.FC<BookmarkListProps> = ({
|
||||
onToggleCollapse={onToggleCollapse}
|
||||
onLogout={onLogout}
|
||||
onOpenSettings={onOpenSettings}
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
relayPool={relayPool}
|
||||
/>
|
||||
|
||||
@@ -130,6 +131,34 @@ export const BookmarkList: React.FC<BookmarkListProps> = ({
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{onRefresh && (
|
||||
<div className="refresh-section" style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.5rem',
|
||||
padding: '1rem',
|
||||
marginTop: '1rem',
|
||||
borderTop: '1px solid var(--border-color)',
|
||||
fontSize: '0.85rem',
|
||||
color: 'var(--text-secondary)'
|
||||
}}>
|
||||
<IconButton
|
||||
icon={faRotate}
|
||||
onClick={onRefresh}
|
||||
title="Refresh bookmarks"
|
||||
ariaLabel="Refresh bookmarks"
|
||||
variant="ghost"
|
||||
disabled={isRefreshing}
|
||||
spin={isRefreshing}
|
||||
/>
|
||||
{lastFetchTime && (
|
||||
<span>
|
||||
Updated {formatDistanceToNow(lastFetchTime, { addSuffix: true })}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="view-mode-controls">
|
||||
|
||||
@@ -94,6 +94,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
setHighlightsLoading,
|
||||
followedPubkeys,
|
||||
isRefreshing,
|
||||
lastFetchTime,
|
||||
handleFetchHighlights,
|
||||
handleRefreshAll
|
||||
} = useBookmarksData({
|
||||
@@ -182,6 +183,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
bookmarksLoading={bookmarksLoading}
|
||||
viewMode={viewMode}
|
||||
isRefreshing={isRefreshing}
|
||||
lastFetchTime={lastFetchTime}
|
||||
onToggleSidebar={() => setIsCollapsed(!isCollapsed)}
|
||||
onLogout={onLogout}
|
||||
onViewModeChange={setViewMode}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faChevronRight, faRightFromBracket, faRightToBracket, faUserCircle, faGear, faRotate, faHome, faPlus } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faChevronRight, faRightFromBracket, faRightToBracket, faUserCircle, faGear, faHome, faPlus, faNewspaper } from '@fortawesome/free-solid-svg-icons'
|
||||
import { Hooks } from 'applesauce-react'
|
||||
import { useEventModel } from 'applesauce-react/hooks'
|
||||
import { Models } from 'applesauce-core'
|
||||
@@ -16,12 +16,10 @@ interface SidebarHeaderProps {
|
||||
onToggleCollapse: () => void
|
||||
onLogout: () => void
|
||||
onOpenSettings: () => void
|
||||
onRefresh?: () => void
|
||||
isRefreshing?: boolean
|
||||
relayPool: RelayPool | null
|
||||
}
|
||||
|
||||
const SidebarHeader: React.FC<SidebarHeaderProps> = ({ onToggleCollapse, onLogout, onOpenSettings, onRefresh, isRefreshing, relayPool }) => {
|
||||
const SidebarHeader: React.FC<SidebarHeaderProps> = ({ onToggleCollapse, onLogout, onOpenSettings, relayPool }) => {
|
||||
const [isConnecting, setIsConnecting] = useState(false)
|
||||
const [showAddModal, setShowAddModal] = useState(false)
|
||||
const navigate = useNavigate()
|
||||
@@ -61,11 +59,6 @@ const SidebarHeader: React.FC<SidebarHeaderProps> = ({ onToggleCollapse, onLogou
|
||||
}
|
||||
|
||||
await createWebBookmark(url, title, description, tags, activeAccount, relayPool, RELAYS)
|
||||
|
||||
// Refresh bookmarks after creating
|
||||
if (onRefresh) {
|
||||
onRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
const profileImage = getProfileImage()
|
||||
@@ -101,6 +94,13 @@ const SidebarHeader: React.FC<SidebarHeaderProps> = ({ onToggleCollapse, onLogou
|
||||
ariaLabel="Home"
|
||||
variant="ghost"
|
||||
/>
|
||||
<IconButton
|
||||
icon={faNewspaper}
|
||||
onClick={() => navigate('/explore')}
|
||||
title="Explore"
|
||||
ariaLabel="Explore"
|
||||
variant="ghost"
|
||||
/>
|
||||
<IconButton
|
||||
icon={faGear}
|
||||
onClick={onOpenSettings}
|
||||
@@ -108,17 +108,6 @@ const SidebarHeader: React.FC<SidebarHeaderProps> = ({ onToggleCollapse, onLogou
|
||||
ariaLabel="Settings"
|
||||
variant="ghost"
|
||||
/>
|
||||
{onRefresh && (
|
||||
<IconButton
|
||||
icon={faRotate}
|
||||
onClick={onRefresh}
|
||||
title="Refresh bookmarks"
|
||||
ariaLabel="Refresh bookmarks"
|
||||
variant="ghost"
|
||||
disabled={isRefreshing}
|
||||
spin={isRefreshing}
|
||||
/>
|
||||
)}
|
||||
{activeAccount && (
|
||||
<IconButton
|
||||
icon={faPlus}
|
||||
|
||||
@@ -28,6 +28,7 @@ interface ThreePaneLayoutProps {
|
||||
bookmarksLoading: boolean
|
||||
viewMode: ViewMode
|
||||
isRefreshing: boolean
|
||||
lastFetchTime?: number | null
|
||||
onToggleSidebar: () => void
|
||||
onLogout: () => void
|
||||
onViewModeChange: (mode: ViewMode) => void
|
||||
@@ -90,6 +91,7 @@ const ThreePaneLayout: React.FC<ThreePaneLayoutProps> = (props) => {
|
||||
onOpenSettings={props.onOpenSettings}
|
||||
onRefresh={props.onRefresh}
|
||||
isRefreshing={props.isRefreshing}
|
||||
lastFetchTime={props.lastFetchTime}
|
||||
loading={props.bookmarksLoading}
|
||||
relayPool={props.relayPool}
|
||||
settings={props.settings}
|
||||
|
||||
@@ -34,6 +34,7 @@ export const useBookmarksData = ({
|
||||
const [highlightsLoading, setHighlightsLoading] = useState(true)
|
||||
const [followedPubkeys, setFollowedPubkeys] = useState<Set<string>>(new Set())
|
||||
const [isRefreshing, setIsRefreshing] = useState(false)
|
||||
const [lastFetchTime, setLastFetchTime] = useState<number | null>(null)
|
||||
|
||||
const handleFetchContacts = useCallback(async () => {
|
||||
if (!relayPool || !activeAccount) return
|
||||
@@ -93,6 +94,7 @@ export const useBookmarksData = ({
|
||||
await handleFetchBookmarks()
|
||||
await handleFetchHighlights()
|
||||
await handleFetchContacts()
|
||||
setLastFetchTime(Date.now())
|
||||
} catch (err) {
|
||||
console.error('Failed to refresh data:', err)
|
||||
} finally {
|
||||
@@ -119,6 +121,7 @@ export const useBookmarksData = ({
|
||||
setHighlightsLoading,
|
||||
followedPubkeys,
|
||||
isRefreshing,
|
||||
lastFetchTime,
|
||||
handleFetchBookmarks,
|
||||
handleFetchHighlights,
|
||||
handleRefreshAll
|
||||
|
||||
Reference in New Issue
Block a user