-
+
+
+
+
+
+
+ {t('n relays', { n: relaySet.relayUrls.length })}
+
+
-
-
-
-
- {t('n relays', { n: relaySet.relayUrls.length })}
-
-
+ {expandedRelaySetId === relaySet.id &&
}
- {expandedRelaySetId === relaySet.id &&
}
)
}
diff --git a/src/components/FavoriteRelaysSetting/RelaySetList.tsx b/src/components/FavoriteRelaysSetting/RelaySetList.tsx
new file mode 100644
index 0000000..c581a39
--- /dev/null
+++ b/src/components/FavoriteRelaysSetting/RelaySetList.tsx
@@ -0,0 +1,72 @@
+import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
+import {
+ closestCenter,
+ DndContext,
+ DragEndEvent,
+ KeyboardSensor,
+ PointerSensor,
+ useSensor,
+ useSensors
+} from '@dnd-kit/core'
+import { restrictToParentElement, restrictToVerticalAxis } from '@dnd-kit/modifiers'
+import {
+ arrayMove,
+ SortableContext,
+ sortableKeyboardCoordinates,
+ verticalListSortingStrategy
+} from '@dnd-kit/sortable'
+import { useTranslation } from 'react-i18next'
+import PullRelaySetsButton from './PullRelaySetsButton'
+import RelaySet from './RelaySet'
+
+export default function RelaySetList() {
+ const { t } = useTranslation()
+ const { relaySets, reorderRelaySets } = useFavoriteRelays()
+
+ const sensors = useSensors(
+ useSensor(PointerSensor),
+ useSensor(KeyboardSensor, {
+ coordinateGetter: sortableKeyboardCoordinates
+ })
+ )
+
+ const handleDragEnd = (event: DragEndEvent) => {
+ const { active, over } = event
+
+ if (over && active.id !== over.id) {
+ const oldIndex = relaySets.findIndex((item) => item.id === active.id)
+ const newIndex = relaySets.findIndex((item) => item.id === over.id)
+
+ const reorderedSets = arrayMove(relaySets, oldIndex, newIndex)
+ reorderRelaySets(reorderedSets)
+ }
+ }
+
+ return (
+
+
+
+ {t('Relay sets')}
+
+
+
+
+ set.id)}
+ strategy={verticalListSortingStrategy}
+ >
+
+ {relaySets.map((relaySet) => (
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/src/components/FavoriteRelaysSetting/index.tsx b/src/components/FavoriteRelaysSetting/index.tsx
index ffbc66b..0a9c202 100644
--- a/src/components/FavoriteRelaysSetting/index.tsx
+++ b/src/components/FavoriteRelaysSetting/index.tsx
@@ -1,39 +1,18 @@
-import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
-import { useTranslation } from 'react-i18next'
import AddNewRelay from './AddNewRelay'
import AddNewRelaySet from './AddNewRelaySet'
+import FavoriteRelayList from './FavoriteRelayList'
import { RelaySetsSettingComponentProvider } from './provider'
-import RelayItem from './RelayItem'
-import RelaySet from './RelaySet'
+import RelaySetList from './RelaySetList'
import TemporaryRelaySet from './TemporaryRelaySet'
-import PullRelaySetsButton from './PullRelaySetsButton'
export default function FavoriteRelaysSetting() {
- const { t } = useTranslation()
- const { relaySets, favoriteRelays } = useFavoriteRelays()
-
return (
-
-
-
- {t('Relay sets')}
-
-
-
- {relaySets.map((relaySet) => (
-
- ))}
-
+
-
-
{t('Relays')}
- {favoriteRelays.map((relay) => (
-
- ))}
-
+
diff --git a/src/lib/draft-event.ts b/src/lib/draft-event.ts
index fc5be39..977c859 100644
--- a/src/lib/draft-event.ts
+++ b/src/lib/draft-event.ts
@@ -135,7 +135,7 @@ export async function createShortTextNoteDraftEvent(
}
// https://github.com/nostr-protocol/nips/blob/master/51.md
-export function createRelaySetDraftEvent(relaySet: TRelaySet): TDraftEvent {
+export function createRelaySetDraftEvent(relaySet: Omit
): TDraftEvent {
return {
kind: kinds.Relaysets,
content: '',
@@ -312,14 +312,18 @@ export function createProfileDraftEvent(content: string, tags: string[][] = []):
export function createFavoriteRelaysDraftEvent(
favoriteRelays: string[],
- relaySetEvents: Event[]
+ relaySetEventsOrATags: Event[] | string[][]
): TDraftEvent {
const tags: string[][] = []
favoriteRelays.forEach((url) => {
tags.push(buildRelayTag(url))
})
- relaySetEvents.forEach((event) => {
- tags.push(buildATag(event))
+ relaySetEventsOrATags.forEach((eventOrATag) => {
+ if (Array.isArray(eventOrATag)) {
+ tags.push(eventOrATag)
+ } else {
+ tags.push(buildATag(eventOrATag))
+ }
})
return {
kind: ExtendedKind.FAVORITE_RELAYS,
@@ -579,7 +583,7 @@ function extractImagesFromContent(content: string) {
return content.match(/https?:\/\/[^\s"']+\.(jpg|jpeg|png|gif|webp|heic)/gi)
}
-function buildATag(event: Event, upperCase: boolean = false) {
+export function buildATag(event: Event, upperCase: boolean = false) {
const coordinate = getReplaceableCoordinateFromEvent(event)
const hint = client.getEventHint(event.id)
return trimTagEnd([upperCase ? 'A' : 'a', coordinate, hint])
diff --git a/src/lib/event-metadata.ts b/src/lib/event-metadata.ts
index 5457cfd..442fe62 100644
--- a/src/lib/event-metadata.ts
+++ b/src/lib/event-metadata.ts
@@ -1,6 +1,7 @@
import { BIG_RELAY_URLS, POLL_TYPE } from '@/constants'
import { TPollType, TRelayList, TRelaySet } from '@/types'
import { Event, kinds } from 'nostr-tools'
+import { buildATag } from './draft-event'
import { getReplaceableEventIdentifier } from './event'
import { getAmountFromInvoice, getLightningAddressFromProfile } from './lightning'
import { formatPubkey, pubkeyToNpub } from './pubkey'
@@ -91,7 +92,7 @@ export function getRelaySetFromEvent(event: Event): TRelaySet {
name = id
}
- return { id, name, relayUrls }
+ return { id, name, relayUrls, aTag: buildATag(event) }
}
export function getZapInfoFromEvent(receiptEvent: Event) {
diff --git a/src/providers/FavoriteRelaysProvider.tsx b/src/providers/FavoriteRelaysProvider.tsx
index d381345..1fbaf73 100644
--- a/src/providers/FavoriteRelaysProvider.tsx
+++ b/src/providers/FavoriteRelaysProvider.tsx
@@ -21,6 +21,7 @@ type TFavoriteRelaysContext = {
addRelaySets: (newRelaySetEvents: Event[]) => Promise
deleteRelaySet: (id: string) => Promise
updateRelaySet: (newSet: TRelaySet) => Promise
+ reorderRelaySets: (reorderedSets: TRelaySet[]) => Promise
}
const FavoriteRelaysContext = createContext(undefined)
@@ -109,7 +110,15 @@ export function FavoriteRelaysProvider({ children }: { children: React.ReactNode
relaySetEventMap.set(d, event)
}
})
- const uniqueNewRelaySetEvents = Array.from(relaySetEventMap.values())
+ const uniqueNewRelaySetEvents = relaySetIds
+ .map((id, index) => {
+ const event = relaySetEventMap.get(id)
+ if (event) {
+ return event
+ }
+ return storedRelaySetEvents[index] || null
+ })
+ .filter(Boolean) as Event[]
setRelaySetEvents(uniqueNewRelaySetEvents)
await Promise.all(
uniqueNewRelaySetEvents.map((event) => {
@@ -210,6 +219,16 @@ export function FavoriteRelaysProvider({ children }: { children: React.ReactNode
})
}
+ const reorderRelaySets = async (reorderedSets: TRelaySet[]) => {
+ setRelaySets(reorderedSets)
+ const draftEvent = createFavoriteRelaysDraftEvent(
+ favoriteRelays,
+ reorderedSets.map((set) => set.aTag)
+ )
+ const newFavoriteRelaysEvent = await publish(draftEvent)
+ updateFavoriteRelaysEvent(newFavoriteRelaysEvent)
+ }
+
return (
{children}
diff --git a/src/types/index.d.ts b/src/types/index.d.ts
index 5749826..0e93c29 100644
--- a/src/types/index.d.ts
+++ b/src/types/index.d.ts
@@ -59,6 +59,7 @@ export type TWebMetadata = {
export type TRelaySet = {
id: string
+ aTag: string[]
name: string
relayUrls: string[]
}