Skip to content

Commit

Permalink
Add popups to router
Browse files Browse the repository at this point in the history
  • Loading branch information
ai committed Oct 26, 2024
1 parent 41d2054 commit 075d9e9
Show file tree
Hide file tree
Showing 14 changed files with 183 additions and 55 deletions.
17 changes: 14 additions & 3 deletions core/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,17 @@ export function setIsMobile(isSmallScreen: boolean): void {

const testRouter = atom<BaseRoute | undefined>()

export function setBaseTestRoute(route: BaseRoute | undefined): void {
testRouter.set(route)
export function addHashToBaseRoute(
route: BaseRoute | Omit<BaseRoute, 'hash'> | undefined
): BaseRoute | undefined {
if (!route) return undefined
return { hash: '', ...route } as BaseRoute
}

export function setBaseTestRoute(
route: BaseRoute | Omit<BaseRoute, 'hash'> | undefined
): void {
testRouter.set(addHashToBaseRoute(route))
}

export function getTestEnvironment(): EnvironmentAndStore {
Expand All @@ -137,7 +146,9 @@ export function getTestEnvironment(): EnvironmentAndStore {
locale: atom('en'),
logStoreCreator: () => new MemoryStore(),
networkType: () => ({ saveData: undefined, type: undefined }),
openRoute: setBaseTestRoute,
openRoute: route => {
setBaseTestRoute({ ...route, hash: '' })
},
persistentEvents: { addEventListener() {}, removeEventListener() {} },
persistentStore: {},
restartApp: () => {},
Expand Down
1 change: 1 addition & 0 deletions core/fast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ onEnvironment(({ openRoute }) => {
if (notSynced(router.get())) {
openRoute({
params: { category, since },
popups: [],
route: 'fast'
})
}
Expand Down
8 changes: 7 additions & 1 deletion core/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,11 @@ onEnvironment(({ openRoute }) => {
previewUrl.listen(link => {
let page = router.get()
if (page.route === 'add' && page.params.url !== link) {
openRoute({ params: { candidate: undefined, url: link }, route: 'add' })
openRoute({
params: { candidate: undefined, url: link },
popups: [],
route: 'add'
})
}
}),
router.subscribe(({ params, route }) => {
Expand All @@ -368,6 +372,7 @@ onEnvironment(({ openRoute }) => {
} else {
openRoute({
params: { candidate: undefined, url: params.url },
popups: [],
route: 'add'
})
}
Expand Down Expand Up @@ -398,6 +403,7 @@ onEnvironment(({ openRoute }) => {
candidate: candidateUrl,
url: page.params.url
},
popups: [],
route: 'add'
})
}
Expand Down
72 changes: 58 additions & 14 deletions core/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export interface Routes {
welcome: {}
}

export const popupNames = { feed: true, feedUrl: true, post: true }

export type PopupRoute = { param: string; popup: keyof typeof popupNames }

export type RouteName = keyof Routes

type EmptyObject = Record<string, never>
Expand All @@ -44,15 +48,20 @@ export type ParamlessRouteName = {
}[RouteName]

export type Route<Name extends RouteName = RouteName> = Name extends string
? { params: Routes[Name]; redirect?: boolean; route: Name }
? {
params: Routes[Name]
popups: PopupRoute[]
redirect?: boolean
route: Name
}
: never

type StringParams<Object> = {
[K in keyof Object]: Object[K] extends string ? Object[K] : Object[K] | string
}

export type BaseRoute<Name extends RouteName = RouteName> = Name extends string
? { params: StringParams<Routes[Name]>; route: Name }
? { hash: string; params: StringParams<Routes[Name]>; route: Name }
: never

export type BaseRouter = ReadableAtom<BaseRoute | undefined>
Expand All @@ -71,7 +80,7 @@ const SETTINGS = new Set<RouteName>([
const ORGANIZE = new Set<RouteName>(['add', 'categories'])

function open(route: ParamlessRouteName): Route {
return { params: {}, route }
return { params: {}, popups: [], route }
}

function redirect(route: Route): Route {
Expand All @@ -91,7 +100,25 @@ function validateNumber(
}
}

let $router = atom<Route>({ params: {}, route: 'home' })
let $router = atom<Route>({ params: {}, popups: [], route: 'home' })

function checkPopupName(
popup: string | undefined
): popup is keyof typeof popupNames {
return !!popup && popup in popupNames
}

function parsePopups(hash: string): PopupRoute[] {
let popups: PopupRoute[] = []
let parts = hash.split(',')
for (let part of parts) {
let [popup, param] = part.split('=', 2)
if (checkPopupName(popup) && param) {
popups.push({ param, popup })
}
}
return popups
}

export const router = readonlyExport($router)

Expand All @@ -102,10 +129,17 @@ onEnvironment(({ baseRouter }) => {
(route, user, withFeeds, fast, slowUnread) => {
if (!route) {
return open('notFound')
} else if (user) {
} else if (!user) {
if (!GUEST.has(route.route)) {
return open('start')
} else {
return { params: route.params, popups: [], route: route.route }
}
} else {
let popups = parsePopups(route.hash)
if (GUEST.has(route.route) || route.route === 'home') {
if (withFeeds) {
return redirect({ params: {}, route: 'slow' })
return redirect({ params: {}, popups, route: 'slow' })
} else {
return redirect(open('welcome'))
}
Expand All @@ -116,12 +150,14 @@ onEnvironment(({ baseRouter }) => {
} else if (route.route === 'feeds') {
return redirect({
params: { candidate: undefined, url: undefined },
popups,
route: 'add'
})
} else if (route.route === 'fast') {
if (!route.params.category && !fast.isLoading) {
return redirect({
params: { category: fast.categories[0].id },
popups,
route: 'fast'
})
}
Expand All @@ -136,11 +172,12 @@ onEnvironment(({ baseRouter }) => {
if (route.params.since) {
return validateNumber(route.params.since, since => {
return {
...route,
params: {
...route.params,
since
}
},
popups,
route: route.route
}
})
}
Expand All @@ -153,6 +190,7 @@ onEnvironment(({ baseRouter }) => {
if (feedData) {
return redirect({
params: { feed: feedData[0].id || '' },
popups,
route: 'slow'
})
}
Expand All @@ -162,11 +200,12 @@ onEnvironment(({ baseRouter }) => {
if (route.params.page) {
return validateNumber(route.params.page, page => {
return {
...route,
params: {
...route.params,
page
}
},
popups,
route: route.route
}
})
} else {
Expand All @@ -175,19 +214,19 @@ onEnvironment(({ baseRouter }) => {
...route.params,
page: 1
},
popups,
route: 'slow'
}
}
}
} else if (!GUEST.has(route.route)) {
return open('start')
return { params: route.params, popups, route: route.route }
}
return route
},
(oldRoute, newRoute) => {
return (
oldRoute.route === newRoute.route &&
JSON.stringify(oldRoute.params) === JSON.stringify(newRoute.params)
JSON.stringify(oldRoute.params) === JSON.stringify(newRoute.params) &&
JSON.stringify(oldRoute.popups) === JSON.stringify(newRoute.popups)
)
}
)
Expand Down Expand Up @@ -215,26 +254,31 @@ export const backRoute = computed(
if (route === 'add' && params.candidate) {
return {
params: { candidate: undefined, url: params.url },
popups: [],
route: 'add'
}
} else if (route === 'categories' && params.feed) {
return {
params: {},
popups: [],
route: 'categories'
}
} else if (route === 'fast' && params.post) {
return {
params: { category: params.category },
popups: [],
route: 'fast'
}
} else if (route === 'slow' && params.post) {
return {
params: { feed: params.feed },
popups: [],
route: 'slow'
}
} else if (route === 'export' && params.format) {
return {
params: { format: undefined },
popups: [],
route: 'export'
}
}
Expand Down
1 change: 1 addition & 0 deletions core/slow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ onEnvironment(({ openRoute }) => {
if (notSynced(router.get())) {
openRoute({
params: { feed, page },
popups: [],
route: 'slow'
})
}
Expand Down
1 change: 1 addition & 0 deletions core/test/fast.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ test('syncs fast category and since with URL', async () => {
await markReadAndLoadNextFastPosts()
deepStrictEqual(router.get(), {
params: { category: category1, since: 5000 },
popups: [],
route: 'fast'
})

Expand Down
4 changes: 3 additions & 1 deletion core/test/page.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ test('synchronizes params', async () => {
await setTimeout(1)
deepStrictEqual(router.get(), {
params: { candidate: undefined, url: 'https://example.com' },
popups: [],
route: 'add'
})
equal(pages.add().url.get(), 'https://example.com')
Expand All @@ -107,6 +108,7 @@ test('synchronizes params', async () => {
await setTimeout(1)
deepStrictEqual(router.get(), {
params: { candidate: undefined, url: 'https://other.com' },
popups: [],
route: 'add'
})
equal(pages.add().url.get(), 'https://other.com')
Expand All @@ -115,7 +117,7 @@ test('synchronizes params', async () => {
setBaseTestRoute({ params: {}, route: 'notFound' })
pages.add().url.set('https://example.com')
await setTimeout(1)
deepStrictEqual(router.get(), { params: {}, route: 'notFound' })
deepStrictEqual(router.get(), { params: {}, popups: [], route: 'notFound' })
})

test('has under construction pages', () => {
Expand Down
6 changes: 6 additions & 0 deletions core/test/preview.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -632,20 +632,23 @@ test('changes URL during typing in the field', async () => {
test('syncs URL with router', async () => {
deepStrictEqual(router.get(), {
params: { candidate: undefined, url: undefined },
popups: [],
route: 'add'
})

expectRequest('http://example.com').andRespond(404)
setPreviewUrl('example.com')
deepStrictEqual(router.get(), {
params: { candidate: undefined, url: 'http://example.com' },
popups: [],
route: 'add'
})

expectRequest('https://other.com').andRespond(404)
setPreviewUrl('https://other.com')
deepStrictEqual(router.get(), {
params: { candidate: undefined, url: 'https://other.com' },
popups: [],
route: 'add'
})

Expand Down Expand Up @@ -683,6 +686,7 @@ test('show candidate on wide screen', async () => {

deepStrictEqual(router.get(), {
params: { candidate: 'https://a.com/atom', url: 'https://a.com/atom' },
popups: [],
route: 'add'
})
equal(currentCandidate.get(), undefined)
Expand All @@ -704,6 +708,7 @@ test('do not show candidate on mobile screen', async () => {

deepStrictEqual(router.get(), {
params: { candidate: undefined, url: 'https://a.com/atom' },
popups: [],
route: 'add'
})
equal(previewCandidate.get(), undefined)
Expand All @@ -722,6 +727,7 @@ test('redirect to candidates list if no current candidate', async () => {
equal(previewCandidate.get(), undefined)
deepStrictEqual(router.get(), {
params: { candidate: undefined, url: 'https://a.com/atom' },
popups: [],
route: 'add'
})
})
Loading

0 comments on commit 075d9e9

Please sign in to comment.