a mini social media app for small communities

add mentions

Changed files
+69 -56
src
static
templates
components
+8
src/api.v
··· 275 return ctx.redirect('/me') 276 } 277 278 ////// Posts ////// 279 280 @['/api/post/new_post'; post]
··· 275 return ctx.redirect('/me') 276 } 277 278 + @['/api/user/get_name'] 279 + fn (mut app App) api_user_get_name(mut ctx Context, username string) veb.Result { 280 + user := app.get_user_by_name(username) or { 281 + return ctx.server_error('no such user') 282 + } 283 + return ctx.text(user.get_name()) 284 + } 285 + 286 ////// Posts ////// 287 288 @['/api/post/new_post'; post]
+3 -3
src/static/js/post.js
··· 17 var body = element.innerText 18 const matches = body.matchAll(new RegExp(mention_pattern, 'g')) 19 for (const match of matches) { 20 - console.log('found match: ' + match) 21 - const username = match[0].substring(1) 22 - element.innerHTML = element.innerHTML.replaceAll(username, '<a href="/user/' + username + '">' + username + '</a>') 23 } 24 }
··· 17 var body = element.innerText 18 const matches = body.matchAll(new RegExp(mention_pattern, 'g')) 19 for (const match of matches) { 20 + (await fetch('/api/user/get_name?username=' + match[0].substring(2, match[0].length - 1))).text().then(s => { 21 + element.innerHTML = element.innerHTML.replace(match[0], '<a href="/user/' + match[0].substring(2, match[0].length - 1) + '">' + s + '</a>') 22 + }) 23 } 24 }
+2 -2
src/static/themes/hackerman.css
··· 5 --bg: black; 6 --accent-bg: black; 7 --text: green; 8 - --text-light: light-green; 9 --accent: green; 10 - --accent-hover: light-green 11 --accent-text: black; 12 --code: green; 13 --preformatted: green;
··· 5 --bg: black; 6 --accent-bg: black; 7 --text: green; 8 + --text-light: lime; 9 --accent: green; 10 + --accent-hover: lime; 11 --accent-text: black; 12 --code: green; 13 --preformatted: green;
-49
src/templates/components/post.html
··· 1 - <div class="post post-full" onload="render_post_body(@{post.id}, '@@@{app.config.user.username_pattern}')"> 2 - <h2><a href="/user/@{(app.get_user_by_id(post.author_id) or { app.get_unknown_user() }).username}"><strong>@{(app.get_user_by_id(post.author_id) or { app.get_unknown_user() }).get_name()}</strong></a> - @post.title</h2> 3 - <pre id="post-@{post.id}">@post.body</pre> 4 - <p><em>likes: @{app.get_net_likes_for_post(post.id)}</em></p> 5 - <p><em>posted at: @post.posted_at</em></p> 6 - 7 - @if ctx.is_logged_in() 8 - <br> 9 - <div> 10 - <button onclick="like(@post.id)"> 11 - @if app.does_user_like_post(user.id, post.id) 12 - liked :D 13 - @else 14 - like 15 - @end 16 - </button> 17 - <button onclick="dislike(@post.id)"> 18 - @if app.does_user_dislike_post(user.id, post.id) 19 - disliked D: 20 - @else 21 - dislike 22 - @end 23 - </button> 24 - </div> 25 - @end 26 - 27 - @if (ctx.is_logged_in() && user.admin) || (ctx.is_logged_in() && post.author_id == user.id) 28 - <hr> 29 - @if user.admin 30 - <h4>admin powers:</h4> 31 - @else if post.author_id == user.id 32 - <h4>manage post:</h4> 33 - @end 34 - <form action="/api/post/delete" method="post"> 35 - <input 36 - type="number" 37 - name="id" 38 - id="id" 39 - placeholder="post id" 40 - value="@post.id" 41 - required 42 - readonly 43 - hidden 44 - aria-hidden 45 - > 46 - <input type="submit" value="delete"> 47 - </form> 48 - @end 49 - </div>
···
+56 -2
src/templates/post.html
··· 1 @include 'partial/header.html' 2 <script src="/static/js/post.js"></script> 3 - <br> 4 - @include 'components/post.html' 5 @include 'partial/footer.html'
··· 1 @include 'partial/header.html' 2 + 3 <script src="/static/js/post.js"></script> 4 + 5 + <div class="post post-full"> 6 + <h2><a href="/user/@{(app.get_user_by_id(post.author_id) or { app.get_unknown_user() }).username}"><strong>@{(app.get_user_by_id(post.author_id) or { app.get_unknown_user() }).get_name()}</strong></a> - @post.title</h2> 7 + <pre id="post-@{post.id}">@post.body</pre> 8 + <p><em>likes: @{app.get_net_likes_for_post(post.id)}</em></p> 9 + <p><em>posted at: @post.posted_at</em></p> 10 + 11 + @if ctx.is_logged_in() 12 + <br> 13 + <div> 14 + <button onclick="like(@post.id)"> 15 + @if app.does_user_like_post(user.id, post.id) 16 + liked :D 17 + @else 18 + like 19 + @end 20 + </button> 21 + <button onclick="dislike(@post.id)"> 22 + @if app.does_user_dislike_post(user.id, post.id) 23 + disliked D: 24 + @else 25 + dislike 26 + @end 27 + </button> 28 + </div> 29 + @end 30 + 31 + @if (ctx.is_logged_in() && user.admin) || (ctx.is_logged_in() && post.author_id == user.id) 32 + <hr> 33 + @if user.admin 34 + <h4>admin powers:</h4> 35 + @else if post.author_id == user.id 36 + <h4>manage post:</h4> 37 + @end 38 + <form action="/api/post/delete" method="post"> 39 + <input 40 + type="number" 41 + name="id" 42 + id="id" 43 + placeholder="post id" 44 + value="@post.id" 45 + required 46 + readonly 47 + hidden 48 + aria-hidden 49 + > 50 + <input type="submit" value="delete"> 51 + </form> 52 + @end 53 + </div> 54 + 55 + <script type="module"> 56 + await render_post_body(@{post.id}, '@@\\(@{app.config.user.username_pattern}\\)') 57 + </script> 58 + 59 @include 'partial/footer.html'