Release: dev → main (first public release) #258
+17
-1
@@ -94,9 +94,25 @@ const routes = [
|
|||||||
const history =
|
const history =
|
||||||
typeof window !== 'undefined' ? createWebHistory() : createMemoryHistory()
|
typeof window !== 'undefined' ? createWebHistory() : createMemoryHistory()
|
||||||
|
|
||||||
|
// Where the window lands after a navigation. Without this the router keeps the
|
||||||
|
// window's scroll offset, so a view entered from halfway down another one opened
|
||||||
|
// halfway down itself, its heading and tab strip under the nav (operator-flagged
|
||||||
|
// 2026-09-24, Settings entered from a scrolled feed).
|
||||||
|
// - back/forward returns to where that entry was left;
|
||||||
|
// - the SAME view with a new query (a gallery filter, a Browse or
|
||||||
|
// Subscriptions tab) keeps its place — that is not a new page;
|
||||||
|
// - a new view opens at its top.
|
||||||
|
export function scrollBehavior(to, from, savedPosition) {
|
||||||
|
if (savedPosition) return savedPosition
|
||||||
|
if (from.matched.length && to.path === from.path) return false
|
||||||
|
if (to.hash) return { el: to.hash }
|
||||||
|
return { top: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history,
|
history,
|
||||||
routes
|
routes,
|
||||||
|
scrollBehavior
|
||||||
})
|
})
|
||||||
|
|
||||||
const DEFAULT_TITLE = 'FabledCurator'
|
const DEFAULT_TITLE = 'FabledCurator'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect } from 'vitest'
|
import { describe, it, expect } from 'vitest'
|
||||||
import router, { FRONT_DOOR } from '../src/router.js'
|
import router, { FRONT_DOOR, scrollBehavior } from '../src/router.js'
|
||||||
|
|
||||||
describe('router', () => {
|
describe('router', () => {
|
||||||
it('FRONT_DOOR is the post feed', () => {
|
it('FRONT_DOOR is the post feed', () => {
|
||||||
@@ -74,4 +74,26 @@ describe('router', () => {
|
|||||||
expect(r.name).toBe('series-read')
|
expect(r.name).toBe('series-read')
|
||||||
expect(r.meta.immersive).toBe(true)
|
expect(r.meta.immersive).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('scrollBehavior', () => {
|
||||||
|
const at = (path) => ({ path, hash: '', matched: [{}] })
|
||||||
|
|
||||||
|
it('opens a new view at its top, not at the last view\'s offset', () => {
|
||||||
|
expect(scrollBehavior(at('/settings'), at('/latest'), null)).toEqual({ top: 0 })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('back and forward return to where the entry was left', () => {
|
||||||
|
const saved = { left: 0, top: 1234 }
|
||||||
|
expect(scrollBehavior(at('/latest'), at('/settings'), saved)).toBe(saved)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('a new query on the same view keeps its place', () => {
|
||||||
|
expect(scrollBehavior(at('/gallery'), at('/gallery'), null)).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('the first navigation of a page load opens at the top', () => {
|
||||||
|
const initial = { path: '/', hash: '', matched: [] }
|
||||||
|
expect(scrollBehavior(at('/latest'), initial, null)).toEqual({ top: 0 })
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user