fix: atproto oauth dev redirect, tab isolation, and concurrent load guard
- Use buildLoopbackClientId(window.location) for dev to include port in redirect URI - Bind Vite dev server to 127.0.0.1 explicitly - Remove scope override in signInRedirect (use metadata default) - Clear OAuth callback params from URL after session restore - Replace follows badge with DaisyUI tabs (All / Following) - Use separate PublicNoteList instances per tab to isolate v-infinite-scroll state - Add isLoading guard in onLoadMore to prevent concurrent fetches
This commit is contained in:
@@ -19,6 +19,8 @@ const initializeAuth = async () => {
|
||||
did.value = session.did
|
||||
handle.value = resolvedHandle
|
||||
await saveSession(session.did, resolvedHandle)
|
||||
|
||||
window.history.replaceState(null, '', window.location.pathname)
|
||||
} else {
|
||||
const stored = await loadSession()
|
||||
did.value = stored?.did ?? ''
|
||||
|
||||
@@ -15,6 +15,7 @@ export function usePublicNoteList(options?: UsePublicNoteListOptions) {
|
||||
const canLoadMore = computed(() => cursor.value !== undefined)
|
||||
|
||||
const onLoadMore = async () => {
|
||||
if (isLoading.value) return
|
||||
isLoading.value = true
|
||||
|
||||
const path = options?.did?.value ? `/${options.did.value}/notes` : "/notes"
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { BrowserOAuthClient } from '@atproto/oauth-client-browser'
|
||||
import { BrowserOAuthClient, buildLoopbackClientId } from '@atproto/oauth-client-browser'
|
||||
|
||||
const CLIENT_ID = import.meta.env.DEV
|
||||
? 'http://localhost'
|
||||
: 'https://remanso.space/client-metadata.json'
|
||||
const getClientId = () =>
|
||||
import.meta.env.DEV
|
||||
? buildLoopbackClientId(new URL(window.location.origin))
|
||||
: 'https://remanso.space/client-metadata.json'
|
||||
|
||||
let clientPromise: Promise<BrowserOAuthClient> | null = null
|
||||
|
||||
export const getOAuthClient = (): Promise<BrowserOAuthClient> => {
|
||||
if (!clientPromise) {
|
||||
clientPromise = BrowserOAuthClient.load({
|
||||
clientId: CLIENT_ID,
|
||||
clientId: getClientId(),
|
||||
handleResolver: 'https://bsky.social',
|
||||
})
|
||||
}
|
||||
@@ -18,7 +19,7 @@ export const getOAuthClient = (): Promise<BrowserOAuthClient> => {
|
||||
|
||||
export const signInWithHandle = async (handle: string): Promise<void> => {
|
||||
const client = await getOAuthClient()
|
||||
await client.signInRedirect(handle, { scope: 'atproto transition:generic' })
|
||||
await client.signInRedirect(handle)
|
||||
}
|
||||
|
||||
export const restoreSession = async () => {
|
||||
|
||||
@@ -5,11 +5,15 @@ import SignInAtproto from "@/components/SignInAtproto.vue"
|
||||
import { useATProtoLogin } from "@/hooks/useATProtoLogin.hook"
|
||||
import { useFollows } from "@/hooks/useFollows.hook"
|
||||
import { usePublicNoteList } from "@/hooks/usePublicNoteList.hook"
|
||||
import { ref } from "vue"
|
||||
|
||||
const { did, isLoggedIn } = useATProtoLogin()
|
||||
const { follows } = useFollows(did)
|
||||
const { notes, isLoading, canLoadMore, onLoadMore, getAuthor } =
|
||||
usePublicNoteList({ followsFilter: follows })
|
||||
|
||||
const tab = ref<'all' | 'following'>('all')
|
||||
|
||||
const all = usePublicNoteList()
|
||||
const following = usePublicNoteList({ followsFilter: follows })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -19,36 +23,55 @@ const { notes, isLoading, canLoadMore, onLoadMore, getAuthor } =
|
||||
<h1>Remanso notes</h1>
|
||||
<sign-in-atproto />
|
||||
</div>
|
||||
<div v-if="isLoggedIn && follows.size > 0" class="follows-badge">
|
||||
Showing follows only
|
||||
</div>
|
||||
<div v-if="isLoading"></div>
|
||||
<div v-else>
|
||||
<PublicNoteList
|
||||
:notes="notes"
|
||||
:can-load-more="canLoadMore"
|
||||
:on-load-more="onLoadMore"
|
||||
>
|
||||
<template #meta="{ note }">
|
||||
<router-link
|
||||
v-if="getAuthor(note.did)"
|
||||
:to="{
|
||||
name: 'PublicNoteListByDidView',
|
||||
params: { did: note.did },
|
||||
}"
|
||||
class="link link-hover"
|
||||
>
|
||||
{{ getAuthor(note.did) }}
|
||||
</router-link>
|
||||
|
||||
<template v-if="note.publishedAt">
|
||||
<span> • </span>
|
||||
<span>{{ new Date(note.publishedAt).toLocaleDateString() }}</span>
|
||||
</template>
|
||||
<div v-else class="skeleton h-4 w-20"></div>
|
||||
</template>
|
||||
</PublicNoteList>
|
||||
<div v-if="isLoggedIn" role="tablist" class="tabs tabs-border">
|
||||
<a role="tab" class="tab" :class="{ 'tab-active': tab === 'all' }" @click="tab = 'all'">All</a>
|
||||
<a role="tab" class="tab" :class="{ 'tab-active': tab === 'following' }" @click="tab = 'following'">Following</a>
|
||||
</div>
|
||||
|
||||
<PublicNoteList
|
||||
v-if="tab === 'all'"
|
||||
:notes="all.notes.value"
|
||||
:can-load-more="all.canLoadMore.value"
|
||||
:on-load-more="all.onLoadMore"
|
||||
>
|
||||
<template #meta="{ note }">
|
||||
<router-link
|
||||
v-if="all.getAuthor(note.did)"
|
||||
:to="{ name: 'PublicNoteListByDidView', params: { did: note.did } }"
|
||||
class="link link-hover"
|
||||
>
|
||||
{{ all.getAuthor(note.did) }}
|
||||
</router-link>
|
||||
<template v-if="note.publishedAt">
|
||||
<span> • </span>
|
||||
<span>{{ new Date(note.publishedAt).toLocaleDateString() }}</span>
|
||||
</template>
|
||||
<div v-else class="skeleton h-4 w-20"></div>
|
||||
</template>
|
||||
</PublicNoteList>
|
||||
|
||||
<PublicNoteList
|
||||
v-else
|
||||
:notes="following.notes.value"
|
||||
:can-load-more="following.canLoadMore.value"
|
||||
:on-load-more="following.onLoadMore"
|
||||
>
|
||||
<template #meta="{ note }">
|
||||
<router-link
|
||||
v-if="following.getAuthor(note.did)"
|
||||
:to="{ name: 'PublicNoteListByDidView', params: { did: note.did } }"
|
||||
class="link link-hover"
|
||||
>
|
||||
{{ following.getAuthor(note.did) }}
|
||||
</router-link>
|
||||
<template v-if="note.publishedAt">
|
||||
<span> • </span>
|
||||
<span>{{ new Date(note.publishedAt).toLocaleDateString() }}</span>
|
||||
</template>
|
||||
<div v-else class="skeleton h-4 w-20"></div>
|
||||
</template>
|
||||
</PublicNoteList>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -83,11 +106,4 @@ const { notes, isLoading, canLoadMore, onLoadMore, getAuthor } =
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.follows-badge {
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -77,6 +77,9 @@ export default defineConfig(({ command }) => {
|
||||
config.define = {
|
||||
global: {},
|
||||
}
|
||||
config.server = {
|
||||
host: '127.0.0.1',
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
|
||||
Reference in New Issue
Block a user