atproto pastebin service: https://plonk.li

add footer, comments, linenrs etc

Changed files
+87 -14
src
+9
src/mixins/footer.pug
··· 1 + mixin footer() 2 + hr 3 + div.footer 4 + div.left-side 5 + div.right-side 6 + p 7 + | made by 8 + a(href="https://bsky.app/profile/oppi.li") @oppi.li 9 +
+2 -1
src/mixins/post.pug
··· 13 13 | #{paste.lang} 14 14 | · 15 15 | #{paste.code.split('\n').length} loc 16 - 16 + | ·  17 + a(href=`/p/${paste.shortUrl}/#comments`) #{paste.commentCount} #{pluralize(paste.commentCount, 'comment')}
+4
src/mixins/utils.pug
··· 2 2 function randInt(min, max) { 3 3 return Math.floor(Math.random() * (max - min + 1)) + min; 4 4 } 5 + - 6 + function pluralize(count, noun) { 7 + return count==1?noun:`${noun}s`; 8 + } 5 9 - 6 10 function timeDifference(current, previous) { 7 11 if (!current || !previous) {
+19 -2
src/public/styles.css
··· 104 104 hr { 105 105 border: none; 106 106 border-top: 1px solid var(--bg-color-muted); 107 - padding: 1rem; 108 107 } 109 108 110 109 .post-form { ··· 152 151 flex: 1 153 152 } 154 153 155 - .header { 154 + .header, .footer { 156 155 display: flex; 157 156 flex-direction: row; 158 157 justify-content: space-between; ··· 165 164 text-indent: 1px; 166 165 text-overflow: ''; 167 166 } 167 + 168 + .code-line { 169 + display: flex; 170 + } 171 + 172 + .code-line-num { 173 + white-space: pre; 174 + -webkit-user-select: none; 175 + user-select: none; 176 + margin-right: 0.4em; 177 + padding: 0 0.4em 0 0.4em; 178 + color: var(--text-color-muted); 179 + text-align: right; 180 + } 181 + 182 + .code-line-content { 183 + color: var(--text-color); 184 + }
+29 -4
src/routes.ts
··· 105 105 const agent = await getSessionAgent(req, res, ctx); 106 106 const pastes = await ctx.db 107 107 .selectFrom("paste") 108 - .selectAll() 109 - .orderBy("indexedAt", "desc") 108 + .leftJoin("comment", "comment.pasteUri", "paste.uri") 109 + .select([ 110 + "paste.uri", 111 + "paste.shortUrl", 112 + "paste.authorDid", 113 + "paste.code", 114 + "paste.lang", 115 + "paste.title", 116 + "paste.createdAt", 117 + "paste.indexedAt as pasteIndexedAt", 118 + ctx.db.fn.count("comment.uri").as("commentCount") 119 + ]) 120 + .groupBy("paste.uri") 121 + .orderBy("pasteIndexedAt", "desc") 110 122 .limit(25) 111 123 .execute(); 112 124 ··· 130 142 const { authorDid } = req.params; 131 143 const pastes = await ctx.db 132 144 .selectFrom("paste") 133 - .selectAll() 134 - .where("authorDid", "=", authorDid) 145 + .leftJoin("comment", "comment.pasteUri", "paste.uri") 146 + .select([ 147 + "paste.uri", 148 + "paste.shortUrl", 149 + "paste.authorDid as pasteAuthorDid", 150 + "paste.code", 151 + "paste.lang", 152 + "paste.title", 153 + "paste.createdAt as pasteCreatedAt", 154 + "paste.indexedAt as pasteIndexedAt", 155 + ctx.db.fn.count("comment.uri").as("commentCount") 156 + ]) 157 + .groupBy("paste.uri") 158 + .where("pasteAuthorDid", "=", authorDid) 159 + .orderBy("pasteCreatedAt", "desc") 135 160 .execute(); 136 161 let didHandleMap: Record<string, string> = {}; 137 162 didHandleMap[authorDid] = await ctx.resolver.resolveDidToHandle(authorDid);
+3
src/views/index.pug
··· 1 1 include ../mixins/mkPost 2 2 include ../mixins/head 3 3 include ../mixins/header 4 + include ../mixins/footer 4 5 include ../mixins/utils 5 6 include ../mixins/post 6 7 ··· 19 20 "c", 20 21 "c#", 21 22 "c++", 23 + "cobol", 22 24 ].toSorted()) 23 25 doctype html 24 26 html ··· 34 36 each paste in pastes 35 37 - var handle = didHandleMap[paste.authorDid] 36 38 +post(paste, handle, paste.authorDid) 39 + +footer()
+21 -7
src/views/paste.pug
··· 15 15 | #{paste.lang} · 16 16 | #{paste.code.split('\n').length} loc · 17 17 a(href=`/r/${paste.shortUrl}`) raw 18 + | &nbsp;·&nbsp; 19 + | #{comments.length} #{pluralize(comments.length, 'comment')} 18 20 pre 19 - | #{paste.code} 21 + code 22 + - var lines = paste.code.split(/\r?\n|\r|\n/g) 23 + - var tot_chars = lines.length.toString().length 24 + each line, idx in lines 25 + span.code-line 26 + span.code-line-num(id=`L${idx + 1}` style=`min-width: ${tot_chars}ch;`) 27 + | #{idx + 1} 28 + span.code-line-content #{line} 20 29 hr 21 30 22 31 if comments.length != 0 23 - h1 comments 32 + h1(id="comments") comments 24 33 div.comments 25 34 each comment in comments 26 35 div.comment(id=`${encodeURIComponent(comment.uri)}`) ··· 33 42 pre.comment-body #{comment.body} 34 43 hr 35 44 36 - form(action=`/${encodeURIComponent(paste.uri)}/comment` method="post").post-form 37 - div.post-row 38 - textarea#code(name="comment" rows="5" placeholder="add a comment" required).post-input-code 45 + if ownDid 46 + form(action=`/${encodeURIComponent(paste.uri)}/comment` method="post").post-form 47 + div.post-row 48 + textarea#code(name="comment" rows="5" placeholder="add a comment" required).post-input-code 39 49 40 - div.post-submit-row 41 - button(type="submit").post-input-submit zonk! 50 + div.post-submit-row 51 + button(type="submit").post-input-submit zonk! 52 + else 53 + p 54 + a(href="/login") login 55 + |&nbsp;to post a comment