Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add candidate to preview URL #208

Merged
merged 7 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 42 additions & 6 deletions core/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { type LoaderName, loaders } from './loader/index.js'
import { addPost, processOriginPost } from './post.js'
import type { PostsPage } from './posts-page.js'
import { router } from './router.js'
import { showSecondStep } from './two-steps.js'

const ALWAYS_HTTPS = [/^twitter\.com\//]

Expand Down Expand Up @@ -117,9 +116,6 @@ function addCandidate(url: string, candidate: PreviewCandidate): void {

$links.setKey(url, { state: 'processed' })
$candidates.set([...$candidates.get(), candidate])
if ($candidates.get().length === 1) {
if (!isMobile.get()) setPreviewCandidate(url)
}
}

function getLoaderForUrl(url: string): false | PreviewCandidate {
Expand Down Expand Up @@ -256,6 +252,7 @@ export const onPreviewUrlType = debounce((value: string) => {
if (value === '') {
clearPreview()
} else {
currentCandidate.set(undefined)
setPreviewUrl(value)
}
}, 500)
Expand Down Expand Up @@ -285,8 +282,6 @@ export async function setPreviewCandidate(url: string): Promise<void> {
$posts.set(posts)
postsCache.set(url, posts)
}

showSecondStep()
}
}

Expand All @@ -313,6 +308,9 @@ export async function addPreviewCandidate(): Promise<void> {

let inPreview = false

export const currentCandidate = atom<string | undefined>()
let candidateUrl: string

onEnvironment(({ openRoute }) => {
return [
previewUrl.listen(link => {
Expand All @@ -323,6 +321,7 @@ onEnvironment(({ openRoute }) => {
}),
router.subscribe(({ params, route }) => {
if (route === 'add' && params.url !== previewUrl.get()) {
currentCandidate.set(params.candidate)
setPreviewUrl(params.url ?? '')
}
if (route === 'add') {
Expand All @@ -331,6 +330,43 @@ onEnvironment(({ openRoute }) => {
inPreview = false
clearPreview()
}
if (route === 'add' && params.candidate) {
if ($candidates.get().length > 0) {
setPreviewCandidate(params.candidate)
} else {
openRoute({
params: { url: params.url },
route: 'add'
})
}
}
}),
$candidates.listen(candidates => {
let page = router.get()
let currentCandidateUrl = currentCandidate.get()

if (
!isMobile.get() &&
page.route === 'add' &&
page.params.url &&
!page.params.candidate
) {
if (!currentCandidateUrl && candidates[0]) {
candidateUrl = candidates[0].url
} else if (
currentCandidateUrl &&
candidates.find(candidate => candidate.url === currentCandidateUrl)
) {
candidateUrl = currentCandidateUrl
}
openRoute({
params: {
candidate: candidateUrl,
url: page.params.url
},
route: 'add'
})
}
})
]
})
19 changes: 12 additions & 7 deletions core/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { slowCategories } from './slow.js'

export interface Routes {
about: {}
add: { url?: string }
add: { candidate?: string; url?: string }
categories: { feed?: string }
download: {}
fast: { category?: string; post?: string; since?: number }
Expand Down Expand Up @@ -216,20 +216,25 @@ export function removeFeedFromRoute(): void {

export const backRoute = computed<Route | undefined, typeof router>(
router,
route => {
if (route.route === 'categories' && route.params.feed) {
({ params, route }) => {
if (route === 'add' && params.candidate) {
return {
params: { url: params.url },
route: 'add'
}
} else if (route === 'categories' && params.feed) {
return {
params: {},
route: 'categories'
}
} else if (route.route === 'fast' && route.params.post) {
} else if (route === 'fast' && params.post) {
return {
params: { category: route.params.category },
params: { category: params.category },
route: 'fast'
}
} else if (route.route === 'slow' && route.params.post) {
} else if (route === 'slow' && params.post) {
return {
params: { feed: route.params.feed },
params: { feed: params.feed },
route: 'slow'
}
}
Expand Down
27 changes: 27 additions & 0 deletions core/test/preview.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
checkAndRemoveRequestMock,
clearPreview,
createPostsPage,
currentCandidate,
expectRequest,
getFeeds,
getPosts,
Expand Down Expand Up @@ -668,6 +669,11 @@ test('show candidate on wide screen', async () => {
setPreviewUrl('https://a.com/atom')
await setTimeout(10)

deepStrictEqual(router.get(), {
params: { candidate: 'https://a.com/atom', url: 'https://a.com/atom' },
route: 'add'
})
equal(currentCandidate.get(), undefined)
equal(previewCandidate.get(), 'https://a.com/atom')
})

Expand All @@ -684,5 +690,26 @@ test('do not show candidate on mobile screen', async () => {
setPreviewUrl('https://a.com/atom')
await setTimeout(10)

deepStrictEqual(router.get(), {
params: { url: 'https://a.com/atom' },
route: 'add'
})
equal(previewCandidate.get(), undefined)
})

test('redirect to candidates list if no current candidate', async () => {
setBaseTestRoute({
params: {
candidate: 'unknown candidate',
url: 'https://a.com/atom'
},
route: 'add'
})

await setTimeout(10)
equal(previewCandidate.get(), undefined)
deepStrictEqual(router.get(), {
params: { url: 'https://a.com/atom' },
route: 'add'
})
})
54 changes: 43 additions & 11 deletions core/test/two-steps.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import './dom-parser.js'

import { deepStrictEqual, strictEqual } from 'node:assert'
import { afterEach, beforeEach, test } from 'node:test'
import { setTimeout } from 'node:timers/promises'
Expand All @@ -7,37 +9,69 @@ import {
addFeed,
addPost,
backRoute,
checkAndRemoveRequestMock,
expectRequest,
mockRequest,
secondStep,
setBaseTestRoute,
showFirstStep,
showSecondStep,
setIsMobile,
setPreviewUrl,
testFeed,
testPost
} from '../index.js'
import { cleanClientTest, enableClientTest } from './utils.js'

beforeEach(() => {
enableClientTest()
secondStep.set(false)
mockRequest()
})

afterEach(async () => {
await cleanClientTest()
checkAndRemoveRequestMock()
})

test('adds route', () => {
test('works with adds route on wide screen', async () => {
setIsMobile(false)
setBaseTestRoute({ params: {}, route: 'add' })
strictEqual(secondStep.get(), false)
expectRequest('https://a.com/atom').andRespond(
200,
'<feed><title>Atom</title>' +
'<entry><id>2</id><updated>2023-07-01T00:00:00Z</updated></entry>' +
'<entry><id>1</id><updated>2023-06-01T00:00:00Z</updated></entry>' +
'</feed>',
'text/xml'
)
setPreviewUrl('https://a.com/atom')
await setTimeout(10)

showSecondStep()
strictEqual(secondStep.get(), true)
strictEqual(backRoute.get(), undefined)
deepStrictEqual(backRoute.get(), {
params: { url: 'https://a.com/atom' },
route: 'add'
})
})

test('works with adds route on mobile screen', async () => {
setIsMobile(true)
setBaseTestRoute({ params: {}, route: 'add' })
expectRequest('https://a.com/atom').andRespond(
200,
'<feed><title>Atom</title>' +
'<entry><id>2</id><updated>2023-07-01T00:00:00Z</updated></entry>' +
'<entry><id>1</id><updated>2023-06-01T00:00:00Z</updated></entry>' +
'</feed>',
'text/xml'
)
setPreviewUrl('https://a.com/atom')
await setTimeout(10)

showFirstStep()
strictEqual(secondStep.get(), false)
strictEqual(backRoute.get(), undefined)
})

test('works with categories route', async () => {
secondStep.set(false)
setBaseTestRoute({ params: {}, route: 'categories' })
strictEqual(secondStep.get(), false)

Expand All @@ -53,8 +87,7 @@ test('works with categories route', async () => {
})
})

test('works withfast route', async () => {
secondStep.set(false)
test('works with fast route', async () => {
let idA = await addCategory({ title: 'A' })
let feed = await addFeed(testFeed({ categoryId: idA, reading: 'fast' }))
let post = await addPost(testPost({ feedId: feed }))
Expand All @@ -75,7 +108,6 @@ test('works withfast route', async () => {
})

test('works with slow route', async () => {
secondStep.set(false)
let idA = await addCategory({ title: 'A' })
let feed = await addFeed(testFeed({ categoryId: idA, reading: 'slow' }))
let post = await addPost(testPost({ feedId: feed, reading: 'slow' }))
Expand Down
12 changes: 8 additions & 4 deletions web/pages/feeds/add.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
previewPosts,
previewUrl,
previewUrlError,
setPreviewCandidate,
previewMessages as t
} from '@slowreader/core'

import { getURL } from '../../stores/router.js'
import Button from '../../ui/button.svelte'
import CardLink from '../../ui/card-link.svelte'
import CardLinks from '../../ui/card-links.svelte'
Expand Down Expand Up @@ -50,9 +50,13 @@
name={candidate.title}
controls="feeds-add_feed"
current={$previewCandidate === candidate.url}
on:click={() => {
setPreviewCandidate(candidate.url)
}}
href={getURL({
params: {
candidate: candidate.url,
url: $previewUrl
},
route: 'add'
})}
/>
{/each}
</CardLinks>
Expand Down
11 changes: 10 additions & 1 deletion web/stores/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ type PathParams = ParamsFromConfig<ConfigFromRouter<typeof pathRouter>>
export const urlRouter = computed(pathRouter, path => {
if (!path) {
return undefined
} else if (path.route === 'add') {
let params: Routes['add'] = path.params
if ('candidate' in path.search) params.candidate = path.search.candidate
return {
params,
route: path.route
}
} else if (path.route === 'fast') {
let params: Routes['fast'] = path.params
if ('since' in path.search) params.since = Number(path.search.since)
Expand Down Expand Up @@ -90,7 +97,9 @@ export function getURL(to: ParamlessRouteName | Route): string {
} else {
page = to
}
if (page.route === 'fast') {
if (page.route === 'add') {
return moveToSearch(page, { candidate: true })
} else if (page.route === 'fast') {
return moveToSearch(page, { post: true, since: true })
} else if (page.route === 'slow') {
return moveToSearch(page, { page: true, post: true })
Expand Down
4 changes: 0 additions & 4 deletions web/ui/navbar/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
refreshProgress,
router,
secondStep,
showFirstStep,
navbarMessages as t
} from '@slowreader/core'
import { onMount } from 'svelte'
Expand Down Expand Up @@ -59,9 +58,6 @@
href={$backRoute ? getURL($backRoute) : undefined}
icon={mdiChevronLeft}
small
on:click={() => {
if (!$backRoute) showFirstStep()
}}
/>
</div>
<div class={`navbar_refresh-button ${$secondStep ? 'is-hidden' : ''}`}>
Expand Down