Fix drag and drop UI on web
This commit is contained in:
@@ -54,6 +54,7 @@ import * as FeedCard from '#/components/FeedCard'
|
|||||||
import {SearchInput} from '#/components/forms/SearchInput'
|
import {SearchInput} from '#/components/forms/SearchInput'
|
||||||
import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline'
|
import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline'
|
||||||
import {Menu_Stroke2_Corner0_Rounded as DragHandleIcon} from '#/components/icons/Menu'
|
import {Menu_Stroke2_Corner0_Rounded as DragHandleIcon} from '#/components/icons/Menu'
|
||||||
|
import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin'
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
import * as ListCard from '#/components/ListCard'
|
import * as ListCard from '#/components/ListCard'
|
||||||
@@ -90,6 +91,10 @@ type FlatlistSlice =
|
|||||||
type: 'noFollowingFeed'
|
type: 'noFollowingFeed'
|
||||||
key: string
|
key: string
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'noPinnedFeeds'
|
||||||
|
key: string
|
||||||
|
}
|
||||||
|
|
||||||
export function FeedsScreen(_props: Props) {
|
export function FeedsScreen(_props: Props) {
|
||||||
const {
|
const {
|
||||||
@@ -221,14 +226,19 @@ const FeedsScreenInner = React.memo(
|
|||||||
key: 'pinnedFeedsSection',
|
key: 'pinnedFeedsSection',
|
||||||
type: 'pinnedFeedsSection',
|
type: 'pinnedFeedsSection',
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasFollowingFeed && pinnedCount > 0) {
|
if (!hasFollowingFeed) {
|
||||||
slices.push({
|
slices.push({
|
||||||
key: 'noFollowingFeed',
|
key: 'noFollowingFeed',
|
||||||
type: 'noFollowingFeed',
|
type: 'noFollowingFeed',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
slices.push({
|
||||||
|
key: 'noPinnedFeeds',
|
||||||
|
type: 'noPinnedFeeds',
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
slices.push({
|
slices.push({
|
||||||
key: 'savedFeedNoResults',
|
key: 'savedFeedNoResults',
|
||||||
@@ -307,11 +317,33 @@ const FeedsScreenInner = React.memo(
|
|||||||
<NoFollowingFeed />
|
<NoFollowingFeed />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
} else if (item.type === 'noPinnedFeeds') {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
pal.border,
|
||||||
|
a.flex_row,
|
||||||
|
a.align_center,
|
||||||
|
a.gap_sm,
|
||||||
|
{
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 16,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<PinIcon size="sm" fill={pal.colors.textLight} />
|
||||||
|
<Text type="md" style={pal.textLight}>
|
||||||
|
<Trans>You don't have any pinned feeds.</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
pal.border,
|
pal.border,
|
||||||
|
pal.textLight,
|
||||||
|
pal.colors,
|
||||||
overlayY,
|
overlayY,
|
||||||
overlayVisible,
|
overlayVisible,
|
||||||
setOverlayFeed,
|
setOverlayFeed,
|
||||||
@@ -422,14 +454,24 @@ const PinnedFeedsSection = React.memo(function PinnedFeedsSection({
|
|||||||
const isDraggingRef = React.useRef(false)
|
const isDraggingRef = React.useRef(false)
|
||||||
|
|
||||||
// Keep ref in sync with server feeds
|
// Keep ref in sync with server feeds
|
||||||
// Always sync unless actively dragging, to handle pin/unpin updates
|
// Merge changes: keep local order for existing feeds, add new ones, remove deleted ones
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!isDraggingRef.current) {
|
if (!isDraggingRef.current) {
|
||||||
// Check if feeds actually changed (different items or order from server)
|
const currentIds = new Set(feedsRef.current.map(f => f.config.id))
|
||||||
const currentIds = feedsRef.current.map(f => f.config.id).join(',')
|
const serverIds = new Set(serverFeeds.map(f => f.config.id))
|
||||||
const serverIds = serverFeeds.map(f => f.config.id).join(',')
|
|
||||||
if (currentIds !== serverIds) {
|
// Find new feeds (in server but not local) and removed feeds (in local but not server)
|
||||||
feedsRef.current = serverFeeds
|
const newFeeds = serverFeeds.filter(f => !currentIds.has(f.config.id))
|
||||||
|
const removedIds = new Set(
|
||||||
|
[...currentIds].filter(id => !serverIds.has(id)),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (newFeeds.length > 0 || removedIds.size > 0) {
|
||||||
|
// Keep existing feeds in their current order, remove deleted, add new at end
|
||||||
|
const updatedFeeds = feedsRef.current
|
||||||
|
.filter(f => !removedIds.has(f.config.id))
|
||||||
|
.concat(newFeeds)
|
||||||
|
feedsRef.current = updatedFeeds
|
||||||
forceRender(n => n + 1)
|
forceRender(n => n + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1153,6 +1195,7 @@ function DragOverlay({
|
|||||||
visible: Animated.SharedValue<number>
|
visible: Animated.SharedValue<number>
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const {isMobile} = useWebMediaQueries()
|
||||||
|
|
||||||
// Position overlay at finger position, offset by half item height (~30px) to center it
|
// Position overlay at finger position, offset by half item height (~30px) to center it
|
||||||
const animatedStyle = useAnimatedStyle(() => {
|
const animatedStyle = useAnimatedStyle(() => {
|
||||||
@@ -1168,11 +1211,13 @@ function DragOverlay({
|
|||||||
<Animated.View
|
<Animated.View
|
||||||
style={[
|
style={[
|
||||||
animatedStyle,
|
animatedStyle,
|
||||||
|
a.mx_auto,
|
||||||
{
|
{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
zIndex: 1000,
|
zIndex: 1000,
|
||||||
|
maxWidth: isMobile ? undefined : 600,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
pointerEvents="none">
|
pointerEvents="none">
|
||||||
|
|||||||
Reference in New Issue
Block a user