diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/geddit.js | 2 | ||||
-rw-r--r-- | src/mixins/header.pug | 4 | ||||
-rw-r--r-- | src/mixins/subUtils.pug | 49 | ||||
-rw-r--r-- | src/public/styles.css | 23 | ||||
-rw-r--r-- | src/routes/index.js | 32 | ||||
-rw-r--r-- | src/views/index.pug | 49 | ||||
-rw-r--r-- | src/views/sub-search.pug | 36 |
7 files changed, 146 insertions, 49 deletions
diff --git a/src/geddit.js b/src/geddit.js index aee7703..d81cedf 100644 --- a/src/geddit.js +++ b/src/geddit.js | |||
@@ -263,7 +263,7 @@ class Geddit { | |||
263 | 263 | ||
264 | const params = { | 264 | const params = { |
265 | limit: 25, | 265 | limit: 25, |
266 | include_over_18: true, | 266 | include_over_18: false, |
267 | }; | 267 | }; |
268 | 268 | ||
269 | return await fetch( | 269 | return await fetch( |
diff --git a/src/mixins/header.pug b/src/mixins/header.pug index 4bec1f8..9cf1e1a 100644 --- a/src/mixins/header.pug +++ b/src/mixins/header.pug | |||
@@ -5,9 +5,9 @@ mixin header(user) | |||
5 | div.header-item | 5 | div.header-item |
6 | a(href=`/r/all`) all | 6 | a(href=`/r/all`) all |
7 | div.header-item | 7 | div.header-item |
8 | a(href=`/r/popular`) popular | 8 | a(href=`/search`) search |
9 | div.header-item | 9 | div.header-item |
10 | a(href=`/subs`) subscriptions | 10 | a(href=`/subs`) subs |
11 | if user | 11 | if user |
12 | div.header-item | 12 | div.header-item |
13 | a(href='/dashboard') #{user.username} | 13 | a(href='/dashboard') #{user.username} |
diff --git a/src/mixins/subUtils.pug b/src/mixins/subUtils.pug new file mode 100644 index 0000000..7f40bf4 --- /dev/null +++ b/src/mixins/subUtils.pug | |||
@@ -0,0 +1,49 @@ | |||
1 | - | ||
2 | script(defer). | ||
3 | async function toggleSub(sub) { | ||
4 | let thinger = document.getElementById(`thinger_${sub}`); | ||
5 | if (thinger.innerText === 'unsubscribe') { | ||
6 | await doThing(sub, 'unsubscribe'); | ||
7 | } else { | ||
8 | await doThing(sub, 'subscribe'); | ||
9 | } | ||
10 | } | ||
11 | |||
12 | function getCookie(name) { | ||
13 | const value = `; ${document.cookie}`; | ||
14 | const parts = value.split(`; ${name}=`); | ||
15 | if (parts.length === 2) return parts.pop().split(";").shift(); | ||
16 | } | ||
17 | |||
18 | async function doThing(sub, thing) { | ||
19 | const jwtToken = getCookie("auth_token"); | ||
20 | const response = await fetch(`/${thing}`, { | ||
21 | method: 'POST', | ||
22 | headers: { | ||
23 | 'Authorization': `Bearer ${jwtToken}`, | ||
24 | 'Content-Type': 'application/json', | ||
25 | }, | ||
26 | body: JSON.stringify({ subreddit: sub }), | ||
27 | }); | ||
28 | |||
29 | let thinger = document.getElementById(`thinger_${sub}`); | ||
30 | if (thing === 'subscribe') { | ||
31 | thinger.innerText = 'unsubscribe'; | ||
32 | } else { | ||
33 | thinger.innerText = 'subscribe'; | ||
34 | } | ||
35 | |||
36 | if (!response.ok) { | ||
37 | console.error(response); | ||
38 | console.error(`Failed to do ${thing}`); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | function toggleDetails(details_id) { | ||
43 | var detailsElement = document.getElementById(details_id); | ||
44 | if (detailsElement) { | ||
45 | detailsElement.open = !detailsElement.open; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | |||
diff --git a/src/public/styles.css b/src/public/styles.css index ba2940d..3b3e80d 100644 --- a/src/public/styles.css +++ b/src/public/styles.css | |||
@@ -542,3 +542,26 @@ form input[type="submit"]:hover { | |||
542 | .invite-link { | 542 | .invite-link { |
543 | font-family: monospace; | 543 | font-family: monospace; |
544 | } | 544 | } |
545 | |||
546 | .search-bar { | ||
547 | display: flex; | ||
548 | flex-direction: row; | ||
549 | justify-content: space-evenly; | ||
550 | width: 100%; | ||
551 | gap: 10px; | ||
552 | } | ||
553 | |||
554 | .search-input { | ||
555 | flex: 9; | ||
556 | } | ||
557 | |||
558 | .search-button { | ||
559 | flex: 1; | ||
560 | padding: 10px; | ||
561 | } | ||
562 | |||
563 | .search-results { | ||
564 | display: flex; | ||
565 | flex-direction: column; | ||
566 | gap: 20px; | ||
567 | } | ||
diff --git a/src/routes/index.js b/src/routes/index.js index e585d3d..c56b73e 100644 --- a/src/routes/index.js +++ b/src/routes/index.js | |||
@@ -103,6 +103,38 @@ router.get("/subs", authenticateToken, async (req, res) => { | |||
103 | res.render("subs", { subs, user: req.user }); | 103 | res.render("subs", { subs, user: req.user }); |
104 | }); | 104 | }); |
105 | 105 | ||
106 | // GET /search-subreddits | ||
107 | router.get("/search", authenticateToken, async (req, res) => { | ||
108 | if (!req.query || !req.query.q) { | ||
109 | res.render("sub-search", {}); | ||
110 | } else { | ||
111 | const { q, options } = req.query.q.split(/\s+/).reduce( | ||
112 | (acc, word) => { | ||
113 | if (word.startsWith("+")) { | ||
114 | acc.options.push(word.slice(1)); | ||
115 | } else { | ||
116 | acc.q += `${word} `; | ||
117 | } | ||
118 | return acc; | ||
119 | }, | ||
120 | { options: [], q: "" }, | ||
121 | ); | ||
122 | |||
123 | const { items, after } = await G.searchSubreddits(q, { | ||
124 | include_over_18: options.includes("nsfw"), | ||
125 | }); | ||
126 | const subs = db | ||
127 | .query("SELECT subreddit FROM subscriptions WHERE user_id = $id") | ||
128 | .all({ id: req.user.id }) | ||
129 | .map((res) => res.subreddit); | ||
130 | const message = | ||
131 | items.length === 0 | ||
132 | ? "no results found" | ||
133 | : `showing ${items.length} results`; | ||
134 | res.render("sub-search", { items, subs, after, message }); | ||
135 | } | ||
136 | }); | ||
137 | |||
106 | // GET /dashboard | 138 | // GET /dashboard |
107 | router.get("/dashboard", authenticateToken, async (req, res) => { | 139 | router.get("/dashboard", authenticateToken, async (req, res) => { |
108 | let invites = null; | 140 | let invites = null; |
diff --git a/src/views/index.pug b/src/views/index.pug index 140cd57..636f9ac 100644 --- a/src/views/index.pug +++ b/src/views/index.pug | |||
@@ -5,50 +5,7 @@ include ../utils | |||
5 | doctype html | 5 | doctype html |
6 | html | 6 | html |
7 | +head("home") | 7 | +head("home") |
8 | script(defer). | 8 | include ../mixins/subUtils |
9 | async function subscribe(sub) { | ||
10 | await doThing(sub, 'subscribe'); | ||
11 | } | ||
12 | |||
13 | async function unsubscribe(sub) { | ||
14 | await doThing(sub, 'unsubscribe'); | ||
15 | } | ||
16 | |||
17 | function getCookie(name) { | ||
18 | const value = `; ${document.cookie}`; | ||
19 | const parts = value.split(`; ${name}=`); | ||
20 | if (parts.length === 2) return parts.pop().split(";").shift(); | ||
21 | } | ||
22 | |||
23 | async function doThing(sub, thing) { | ||
24 | const jwtToken = getCookie("auth_token"); | ||
25 | const response = await fetch(`/${thing}`, { | ||
26 | method: 'POST', | ||
27 | headers: { | ||
28 | 'Authorization': `Bearer ${jwtToken}`, | ||
29 | 'Content-Type': 'application/json', | ||
30 | }, | ||
31 | body: JSON.stringify({ subreddit: sub }), | ||
32 | }); | ||
33 | |||
34 | let thinger = document.getElementById('thinger'); | ||
35 | if (thing == 'subscribe') { | ||
36 | thinger.innerText = 'unsubscribe'; | ||
37 | } else { | ||
38 | thinger.innerText = 'subscribe'; | ||
39 | } | ||
40 | |||
41 | if (!response.ok) { | ||
42 | console.error(`Failed to do ${thing}`); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | function toggleDetails(details_id) { | ||
47 | var detailsElement = document.getElementById(details_id); | ||
48 | if (detailsElement) { | ||
49 | detailsElement.open = !detailsElement.open; | ||
50 | } | ||
51 | } | ||
52 | 9 | ||
53 | body | 10 | body |
54 | main#content | 11 | main#content |
@@ -64,9 +21,9 @@ html | |||
64 | if !isMulti | 21 | if !isMulti |
65 | div#button-container | 22 | div#button-container |
66 | if isSubbed | 23 | if isSubbed |
67 | button(onclick=`unsubscribe('${subreddit}')`)#thinger unsubscribe | 24 | button(onclick=`toggleSub('${subreddit}')` id=`thinger_${subreddit}`) unsubscribe |
68 | else | 25 | else |
69 | button(onclick=`subscribe('${subreddit}')`)#thinger subscribe | 26 | button(onclick=`toggleSub('${subreddit}')` id=`thinger_${subreddit}`) subscribe |
70 | if about && !isMulti | 27 | if about && !isMulti |
71 | p #{about.public_description} | 28 | p #{about.public_description} |
72 | else | 29 | else |
diff --git a/src/views/sub-search.pug b/src/views/sub-search.pug new file mode 100644 index 0000000..4fa707e --- /dev/null +++ b/src/views/sub-search.pug | |||
@@ -0,0 +1,36 @@ | |||
1 | include ../mixins/header | ||
2 | include ../mixins/head | ||
3 | |||
4 | doctype html | ||
5 | html | ||
6 | +head("search subreddits") | ||
7 | include ../mixins/subUtils | ||
8 | body | ||
9 | main#content | ||
10 | +header(user) | ||
11 | div.hero | ||
12 | h1 search subreddits | ||
13 | form(action="/search" method="get").search-bar | ||
14 | input(type="text" name="q" placeholder="search subreddits (add +nsfw to include over-18 results)" required).search-input | ||
15 | button(type="submit").search-button go | ||
16 | if message | ||
17 | div.search-message | ||
18 | | #{message} | ||
19 | if items | ||
20 | div.search-results | ||
21 | each i in items | ||
22 | div.search-result | ||
23 | - var subreddit = i.data.display_name | ||
24 | - var isSubbed = subs.includes(subreddit) | ||
25 | div.sub-title | ||
26 | h3 | ||
27 | a(href=`/r/${subreddit}`) | ||
28 | | r/#{subreddit} | ||
29 | div#button-container | ||
30 | if isSubbed | ||
31 | button(onclick=`toggleSub('${subreddit}')` id=`thinger_${subreddit}`) unsubscribe | ||
32 | else | ||
33 | button(onclick=`toggleSub('${subreddit}')` id=`thinger_${subreddit}`) subscribe | ||
34 | |||
35 | if i.data.public_description | ||
36 | p #{i.data.public_description} | ||