tangled
alpha
login
or
join now
finxol.io
/
bookmarker
0
fork
atom
A very simple bookmarking webapp
bookmarker.finxol.deno.net/
0
fork
atom
overview
issues
pulls
pipelines
feat: add new bookmark page
finxol.io
1 month ago
85fb413c
546483e9
verified
This commit was signed with the committer's
known signature
.
finxol.io
SSH Key Fingerprint:
SHA256:olFE3asYdoBMScuJOt60UxXdJ0RFdGv5kVKrdOtIcPI=
1/1
deploy.yaml
success
11s
+99
-7
4 changed files
expand all
collapse all
unified
split
src
routeTree.gen.ts
routes
__root.tsx
index.tsx
new.tsx
+21
-3
src/routeTree.gen.ts
···
9
9
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
10
11
11
import { Route as rootRouteImport } from './routes/__root'
12
12
+
import { Route as NewRouteImport } from './routes/new'
12
13
import { Route as AccountRouteImport } from './routes/account'
13
14
import { Route as AboutRouteImport } from './routes/about'
14
15
import { Route as IndexRouteImport } from './routes/index'
15
16
17
17
+
const NewRoute = NewRouteImport.update({
18
18
+
id: '/new',
19
19
+
path: '/new',
20
20
+
getParentRoute: () => rootRouteImport,
21
21
+
} as any)
16
22
const AccountRoute = AccountRouteImport.update({
17
23
id: '/account',
18
24
path: '/account',
···
33
39
'/': typeof IndexRoute
34
40
'/about': typeof AboutRoute
35
41
'/account': typeof AccountRoute
42
42
+
'/new': typeof NewRoute
36
43
}
37
44
export interface FileRoutesByTo {
38
45
'/': typeof IndexRoute
39
46
'/about': typeof AboutRoute
40
47
'/account': typeof AccountRoute
48
48
+
'/new': typeof NewRoute
41
49
}
42
50
export interface FileRoutesById {
43
51
__root__: typeof rootRouteImport
44
52
'/': typeof IndexRoute
45
53
'/about': typeof AboutRoute
46
54
'/account': typeof AccountRoute
55
55
+
'/new': typeof NewRoute
47
56
}
48
57
export interface FileRouteTypes {
49
58
fileRoutesByFullPath: FileRoutesByFullPath
50
50
-
fullPaths: '/' | '/about' | '/account'
59
59
+
fullPaths: '/' | '/about' | '/account' | '/new'
51
60
fileRoutesByTo: FileRoutesByTo
52
52
-
to: '/' | '/about' | '/account'
53
53
-
id: '__root__' | '/' | '/about' | '/account'
61
61
+
to: '/' | '/about' | '/account' | '/new'
62
62
+
id: '__root__' | '/' | '/about' | '/account' | '/new'
54
63
fileRoutesById: FileRoutesById
55
64
}
56
65
export interface RootRouteChildren {
57
66
IndexRoute: typeof IndexRoute
58
67
AboutRoute: typeof AboutRoute
59
68
AccountRoute: typeof AccountRoute
69
69
+
NewRoute: typeof NewRoute
60
70
}
61
71
62
72
declare module '@tanstack/solid-router' {
63
73
interface FileRoutesByPath {
74
74
+
'/new': {
75
75
+
id: '/new'
76
76
+
path: '/new'
77
77
+
fullPath: '/new'
78
78
+
preLoaderRoute: typeof NewRouteImport
79
79
+
parentRoute: typeof rootRouteImport
80
80
+
}
64
81
'/account': {
65
82
id: '/account'
66
83
path: '/account'
···
89
106
IndexRoute: IndexRoute,
90
107
AboutRoute: AboutRoute,
91
108
AccountRoute: AccountRoute,
109
109
+
NewRoute: NewRoute,
92
110
}
93
111
export const routeTree = rootRouteImport
94
112
._addFileChildren(rootRouteChildren)
+8
-3
src/routes/__root.tsx
···
25
25
return (
26
26
<main>
27
27
<header>
28
28
-
<Link to="/">
29
29
-
Bookmarker
30
30
-
</Link>
28
28
+
<div>
29
29
+
<Link to="/">
30
30
+
Bookmarker
31
31
+
</Link>
32
32
+
<Link to="/new">
33
33
+
New Bookmark
34
34
+
</Link>
35
35
+
</div>
31
36
{!query.isPending && query.data &&
32
37
(
33
38
<Link to="/account">
+1
-1
src/routes/index.tsx
···
9
9
10
10
function Index() {
11
11
const query = useQuery(() => ({
12
12
-
queryKey: [client.api.v1.bookmarks.all.$url()],
12
12
+
queryKey: [client.api.v1.bookmarks.all.$url().pathname],
13
13
queryFn: async () => {
14
14
const res = await client.api.v1.bookmarks.all.$get()
15
15
if (res.ok) {
+69
src/routes/new.tsx
···
1
1
+
import { createFileRoute, useNavigate } from "@tanstack/solid-router"
2
2
+
import { useMutation, useQueryClient } from "@tanstack/solid-query"
3
3
+
import { createSignal } from "solid-js"
4
4
+
import { client } from "../apiclient.ts"
5
5
+
6
6
+
export const Route = createFileRoute("/new")({
7
7
+
component: RouteComponent,
8
8
+
})
9
9
+
10
10
+
function RouteComponent() {
11
11
+
const queryClient = useQueryClient()
12
12
+
const navigate = useNavigate()
13
13
+
const [url, setUrl] = createSignal("")
14
14
+
15
15
+
const addBookmark = useMutation(() => ({
16
16
+
mutationFn: async (url: string) => {
17
17
+
const res = await client.api.v1.bookmarks.add.$post({
18
18
+
form: { url },
19
19
+
})
20
20
+
if (!res.ok) {
21
21
+
const data = await res.json()
22
22
+
throw new Error(
23
23
+
"error" in data ? data.error : "Failed to add bookmark",
24
24
+
)
25
25
+
}
26
26
+
return await res.json()
27
27
+
},
28
28
+
onSuccess: async () => {
29
29
+
await queryClient.invalidateQueries({
30
30
+
queryKey: [client.api.v1.bookmarks.all.$url().pathname],
31
31
+
})
32
32
+
navigate({ to: "/" })
33
33
+
},
34
34
+
}))
35
35
+
36
36
+
const handleSubmit = (e: SubmitEvent) => {
37
37
+
e.preventDefault()
38
38
+
const value = url().trim()
39
39
+
if (value) {
40
40
+
addBookmark.mutate(value)
41
41
+
}
42
42
+
}
43
43
+
44
44
+
return (
45
45
+
<div>
46
46
+
<h2>Add a new bookmark</h2>
47
47
+
<form onSubmit={handleSubmit}>
48
48
+
<label for="url">URL</label>
49
49
+
<input
50
50
+
id="url"
51
51
+
type="url"
52
52
+
required
53
53
+
placeholder="https://example.com"
54
54
+
value={url()}
55
55
+
onInput={(e) => setUrl(e.currentTarget.value)}
56
56
+
disabled={addBookmark.isPending}
57
57
+
/>
58
58
+
<button type="submit" disabled={addBookmark.isPending}>
59
59
+
{addBookmark.isPending ? "Adding..." : "Add bookmark"}
60
60
+
</button>
61
61
+
</form>
62
62
+
{addBookmark.isError && (
63
63
+
<p style="color: red;">
64
64
+
{addBookmark.error?.message ?? "Failed to add bookmark"}
65
65
+
</p>
66
66
+
)}
67
67
+
</div>
68
68
+
)
69
69
+
}