Skip to content

Commit

Permalink
feat: finalize restore last session
Browse files Browse the repository at this point in the history
  • Loading branch information
AlejandroAkbal committed Jul 6, 2023
1 parent b99ae98 commit f2db99b
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 59 deletions.
9 changes: 9 additions & 0 deletions assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,20 @@
/*
* NOT TO BE USED DIRECTLY AS CSS
* IN CLASSES IT SHOULD BE USED AS `focus-visible:focus-util`
* TODO: @deprecated
*/
.focus-util {
@apply outline-none ring-2 ring-base-content-highlight;
}

/*
* NOT TO BE USED DIRECTLY AS CSS
* IN CLASSES IT SHOULD BE USED AS `focus-visible:focus-outline-util`
*/
.focus-outline-util {
@apply outline outline-2 outline-offset-2 outline-base-content-highlight;
}

/*
* NOT TO BE USED DIRECTLY AS CSS
* IN CLASSES IT SHOULD BE USED AS `hover:hover-text-util`
Expand Down
160 changes: 104 additions & 56 deletions components/posts/RestoreLastSessionPopup.vue
Original file line number Diff line number Diff line change
@@ -1,88 +1,136 @@
<script setup>
import { ArrowUpIcon } from '@heroicons/vue/24/solid'
import { useToggle } from '@vueuse/core'
const [isActive, toggleIsActive] = useToggle(false)
const userSettings = useUserSettings()
import { useRestoreLastSessionPopup } from '~/composables/useRestoreLastSessionPopup'
import { toast } from 'vue-sonner'
import qs from 'qs'
import { Dialog, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'
const router = useRouter()
const { isPremium } = useUserData()
const { lastPostsPage, isMenuActive, toggleMenu } = useRestoreLastSessionPopup()
const bodyText = computed(() => {
if (!userSettings.lastPostsPage) {
if (!lastPostsPage.value) {
return null
}
const lastPostsPageRoute = router.resolve(userSettings.lastPostsPage)
/**
* This is a fix, because using router.resolve() does not parse with `qs.parse()`
*/
const lastPostsPageQuery = qs.parse(lastPostsPage.value)
const lastPostsPageUrl = new URL(lastPostsPageRoute.fullPath, window.location.origin)
let text = `Get back`
const tags = lastPostsPageUrl.searchParams.get('tags')?.split('|')
const page = lastPostsPageUrl.searchParams.get('page')
const filters = lastPostsPageUrl.searchParams.get('filters')
let text = `You were`
if (lastPostsPageQuery.page) {
text += ` to page ${lastPostsPageQuery.page}`
}
if (page) {
text += `on page ${page}`
// Use "to" or "of" depending on the page
if (lastPostsPageQuery.page) {
text += ` of`
} else {
text += ` to`
}
if (tags && tags.length) {
text += `with tags ${tags.join(', ')}`
text += ` posts`
if (lastPostsPageQuery.tags?.length) {
const tags = lastPostsPageQuery.tags.split('|')
text += ` tagged with ${tags.join(', ')}`
}
if (filters) {
// TODO
if (lastPostsPageQuery.filter) {
const filters = Object.keys(lastPostsPageQuery.filter)
text += `, and ${filters.join(', ')} filter`
if (filters.length > 1) {
text += 's'
}
}
return text
})
// TODO: Only do this once, when the entire app has been booted
onMounted(() => {
if (!userSettings.lastPostsPage) {
function onClick() {
if (!isPremium.value) {
toast.error('[Premium feature] Restore last session is only available for Premium users')
return
}
toggleIsActive(true)
})
const lastPostsPageRoute = router.resolve(lastPostsPage.value)
function onClick() {
// TODO: Navigate to userSettings.lastPostsPage while doing a full reload
// TODO: Add analytics to URL
// TODO: Skip if not Premium and show a Toast
const lastPostsPageUrl = new URL(lastPostsPageRoute.fullPath, window.location.origin)
window.location.assign(lastPostsPageUrl.toString())
}
</script>
<template>
<Teleport to="body">
<transition
enter-active-class="transition ease-out duration-150"
enter-from-class="transform opacity-0 scale-95"
enter-to-class="transform opacity-100 scale-100"
leave-active-class="transition ease-in duration-150"
leave-from-class="transform opacity-100 scale-100"
leave-to-class="transform opacity-0 scale-95"
<TransitionRoot
:show="isMenuActive && lastPostsPage != null"
as="template"
>
<Dialog
as="div"
class="relative z-20"
@close="toggleMenu(false)"
>
<div
v-if="userSettings.lastPostsPage"
class="fixed bottom-10"
<TransitionChild
as="template"
enter="ease-out duration-300"
enter-from="opacity-0"
enter-to="opacity-100"
leave="ease-in duration-200"
leave-from="opacity-100"
leave-to="opacity-0"
>
<span> Restore last session? </span>
<!-- -->
{{ bodyText }}
<button
class="hover:hover-text-util hover:hover-bg-util flex h-12 w-12 items-center justify-center rounded-full bg-base-1000/60 text-base-content-highlight ring-2 ring-base-0/20 backdrop-blur"
type="button"
@click="onClick"
>
Restore
<ArrowUpIcon class="h-6 w-6" />
</button>
<div class="fixed inset-0 bg-base-1000/80 backdrop-blur transition-opacity" />
</TransitionChild>
<div class="fixed inset-0 z-10 overflow-y-auto">
<div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<TransitionChild
as="template"
enter="ease-out duration-300"
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enter-to="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leave-from="opacity-100 translate-y-0 sm:scale-100"
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<DialogPanel
class="relative transform overflow-hidden rounded-lg bg-base-1000 px-4 pb-4 pt-5 text-left shadow-xl ring-1 ring-base-0/10 transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6"
>
<!-- TODO: Add dismiss button -->
<!-- TODO: Add dismiss forever button in dropdown -->
<div>
<DialogTitle
as="h3"
class="text-base font-medium leading-6 tracking-tight text-base-content-highlight"
>
Continue where you left off?
</DialogTitle>
<div class="mt-1 text-sm">
{{ bodyText }}
</div>
</div>
<div class="mt-5 sm:mt-6">
<button
class="hover:hover-text-util focus-visible:focus-outline-util hover:hover-bg-util w-full rounded-md px-3 py-2 text-sm shadow-sm ring-1 ring-base-0/20"
type="button"
@click="onClick"
>
Continue
</button>
</div>
</DialogPanel>
</TransitionChild>
</div>
</div>
</transition>
</Teleport>
</Dialog>
</TransitionRoot>
</template>
16 changes: 16 additions & 0 deletions composables/useRestoreLastSessionPopup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useStorage, useToggle } from '@vueuse/core'

const lastPostsPage = useStorage<string | undefined>('settings-lastPostsPage', undefined, localStorage, {
writeDefaults: false
})

const [isMenuActive, toggleMenu] = useToggle(false)

export function useRestoreLastSessionPopup() {
return {
lastPostsPage,

isMenuActive,
toggleMenu
}
}
22 changes: 20 additions & 2 deletions middleware/restore-last-session.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import { useRestoreLastSessionPopup } from '~/composables/useRestoreLastSessionPopup'

let hasAppBooted = false

export default defineNuxtRouteMiddleware((to, from) => {
const userSettings = useUserSettings()
const { lastPostsPage, toggleMenu } = useRestoreLastSessionPopup()

// Show menu on first app boot
// And skip if going to the same page
if (!hasAppBooted && to.fullPath !== lastPostsPage.value) {
hasAppBooted = true

toggleMenu(true)
return
}

if (to.name !== 'posts') {
return
}

// Skip if same route
if (to.fullPath === from.fullPath) {
return
}

// TODO: Skip if to has default values

userSettings.lastPostsPage = to.fullPath
lastPostsPage.value = to.fullPath
})
2 changes: 1 addition & 1 deletion pages/settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
<ExclamationTriangleIcon class="inline-block h-4 w-4" />
</span>

<span class="block text-sm"> Resets settings, saved posts, and all other app data. </span>
<span class="block text-sm"> Clear settings, saved posts, and all other app data. </span>
</label>

<button
Expand Down
12 changes: 12 additions & 0 deletions test/feature/pages/posts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,4 +391,16 @@ describe('/', async () => {
// TODO
})
})

describe('Restore last session', async () => {
it.skip('renders', async () => {
// TODO: Visit a tag page
// TODO: Visit default page with full reload
// TODO: Check modal is rendered
})

it.skip('restores last session', async () => {
// TODO
})
})
})

0 comments on commit f2db99b

Please sign in to comment.