Skip to content

Commit

Permalink
feat(composable): add openInPopup(route, { width, height }) (#336)
Browse files Browse the repository at this point in the history
Co-authored-by: Sébastien Chopin <seb@nuxt.com>
Co-authored-by: Sébastien Chopin <atinux@gmail.com>
  • Loading branch information
3 people authored Feb 4, 2025
1 parent 6c5c4cd commit e6371c7
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 2 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Nuxt Auth Utils automatically adds some plugins to fetch the current user sessio

```vue
<script setup>
const { loggedIn, user, session, fetch, clear } = useUserSession()
const { loggedIn, user, session, fetch, clear, openInPopup } = useUserSession()
</script>
<template>
Expand All @@ -74,6 +74,8 @@ const { loggedIn, user, session, fetch, clear } = useUserSession()
<div v-else>
<h1>Not logged in</h1>
<a href="/auth/github">Login with GitHub</a>
<!-- or open the OAuth route in a popup -->
<button @click="openInPopup('/auth/github')">Login with GitHub</button>
</div>
</template>
```
Expand Down Expand Up @@ -106,6 +108,10 @@ interface UserSessionComposable {
* Clear the user session and remove the session cookie.
*/
clear: () => Promise<void>
/**
* Open the OAuth route in a popup that auto-closes when successful.
*/
openInPopup: (route: string, size?: { width?: number, height?: number }) => void
}
```

Expand Down
13 changes: 12 additions & 1 deletion playground/app.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
const { user } = useUserSession()
const { user, openInPopup } = useUserSession()
const inPopup = ref(false)
const providers = computed(() =>
[
{
Expand Down Expand Up @@ -205,6 +206,8 @@ const providers = computed(() =>
...p,
prefetch: false,
external: true,
to: inPopup.value ? '#' : p.to,
click: inPopup.value ? () => openInPopup(p.to) : void 0,
})),
)
</script>
Expand Down Expand Up @@ -259,6 +262,14 @@ const providers = computed(() =>
</UHeader>
<UMain>
<UContainer>
<div class="text-xs mt-4">
Popup mode <UToggle
v-model="inPopup"
size="xs"
name="open-in-popup"
label="Open in popup"
/>
</div>
<NuxtPage />
</UContainer>
</UMain>
Expand Down
29 changes: 29 additions & 0 deletions src/runtime/app/composables/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,41 @@ export function useUserSession(): UserSessionComposable {
}
}

const popupListener = (e: StorageEvent) => {
if (e.key === 'temp-nuxt-auth-utils-popup') {
fetch()
window.removeEventListener('storage', popupListener)
}
}
const openInPopup = (route: string, size: { width?: number, height?: number } = {}) => {
// Set a local storage item to tell the popup that we pending auth
localStorage.setItem('temp-nuxt-auth-utils-popup', 'true')

const width = size.width ?? 960
const height = size.height ?? 600
const top = (window.top?.outerHeight ?? 0) / 2
+ (window.top?.screenY ?? 0)
- height / 2
const left = (window.top?.outerWidth ?? 0) / 2
+ (window.top?.screenX ?? 0)
- width / 2

window.open(
route,
'nuxt-auth-utils-popup',
`width=${width}, height=${height}, top=${top}, left=${left}, toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no`,
)

window.addEventListener('storage', popupListener)
}

return {
ready: computed(() => authReadyState.value),
loggedIn: computed(() => Boolean(sessionState.value.user)),
user: computed(() => sessionState.value.user || null),
session: sessionState,
fetch,
openInPopup,
clear,
}
}
7 changes: 7 additions & 0 deletions src/runtime/app/plugins/session.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ export default defineNuxtPlugin(async (nuxtApp) => {
await useUserSession().fetch()
})
}

if (localStorage.getItem('temp-nuxt-auth-utils-popup')) {
// There is a local storage item. That's mean we are coming back in the popup
localStorage.removeItem('temp-nuxt-auth-utils-popup')
const error = useError()
if (!error.value) window.close()
}
})
4 changes: 4 additions & 0 deletions src/runtime/types/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@ export interface UserSessionComposable {
* Clear the user session and remove the session cookie.
*/
clear: () => Promise<void>
/**
* Open the OAuth route in a popup that auto-closes when successful.
*/
openInPopup: (route: string, size?: { width?: number, height?: number }) => void
}

0 comments on commit e6371c7

Please sign in to comment.