+1
-1
config.maple
+1
-1
config.maple
+13
-10
doc/themes.md
+13
-10
doc/themes.md
···
17
17
> is not even close to comprehensive. these are just my personal picks that i
18
18
> found to be comfy with beep!
19
19
20
-
| name | source | css theme url |
21
-
|-------------------------------|-----------------------------------------|-------------------------------------------------------------|
22
-
| sakura | <https://github.com/oxalorg/sakura> | https://cdn.jsdelivr.net/npm/sakura.css/css/sakura.css |
23
-
| water.css (auto) | <https://github.com/kognise/water.css> | https://cdn.jsdelivr.net/npm/water.css@2/out/water.min.css |
24
-
| water.css (dark) | <https://github.com/kognise/water.css> | https://cdn.jsdelivr.net/npm/water.css@2/out/dark.min.css |
25
-
| water.css (light) | <https://github.com/kognise/water.css> | https://cdn.jsdelivr.net/npm/water.css@2/out/light.min.css |
26
-
| kacit | <https://github.com/Kimeiga/kacit> | https://cdn.rawgit.com/Kimeiga/kacit/b3f813ed/kacit.min.css |
20
+
| name | source | css theme url |
21
+
|------------|------------------------------------------|-------------------------------------------------------------------------|
22
+
| sakura | <https://github.com/oxalorg/sakura> | https://cdn.jsdelivr.net/npm/sakura.css/css/sakura.css |
23
+
| water.css | <https://github.com/kognise/water.css> | https://cdn.jsdelivr.net/npm/water.css@2/out/water.min.css |
24
+
| kacit | <https://github.com/Kimeiga/kacit> | https://cdn.rawgit.com/Kimeiga/kacit/b3f813ed/kacit.min.css |
25
+
| pico | <https://github.com/picocss/pico> | https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css |
26
+
| simple.css | <https://github.com/kevquirk/simple.css> | https://unpkg.com/simpledotcss/simple.min.css |
27
27
28
28
> here is a big list of drop-in themes:
29
29
> <https://github.com/dohliam/dropin-minimal-css>
···
38
38
39
39
## built-in
40
40
41
-
| name | based on (if applicable) | css theme url |
42
-
|---------------------------|---------------------------------|-------------------------------|
43
-
| catppuccin-macchiato-pink | water.css + catpuccin macchiato | catppuccin-macchiato-pink.css |
41
+
| name | based on (if applicable) | css theme url |
42
+
|-----------------------------|---------------------------------|---------------------------------|
43
+
| catppuccin-macchiato-pink | water.css + catpuccin macchiato | catppuccin-macchiato-pink.css |
44
+
| catppuccin-macchiato-green | water.css + catpuccin macchiato | catppuccin-macchiato-green.css |
45
+
| catppuccin-macchiato-yellow | water.css + catpuccin macchiato | catppuccin-macchiato-yellow.css |
46
+
| hackerman | simple.css | hackerman.css |
44
47
45
48
> beep also features some built-in themes, some of which are based on the themes
46
49
> present in the "it just works" list!
+3
-2
doc/todo.md
+3
-2
doc/todo.md
···
4
4
5
5
## in-progress
6
6
7
+
- [ ] post:mentioning ('tagging') other users in posts
8
+
7
9
## planing
8
10
9
-
- [ ] site:message of the day (admins can add a welcome message displayed on index.html)
10
-
- [ ] post:mentioning ('tagging') other users in posts
11
11
- [ ] post:replies
12
12
- [ ] post:tags ('hashtags')
13
13
- [ ] post:images (should have a config.maple toggle to enable/disable)
···
27
27
- [x] post:likes/dislikes
28
28
- [ ] ~~site:stylesheet (and a toggle for html-only mode)~~
29
29
- replaced with per-user optional stylesheets
30
+
- [x] site:message of the day (admins can add a welcome message displayed on index.html)
+27
-1
src/api.v
+27
-1
src/api.v
···
2
2
3
3
import veb
4
4
import auth
5
-
import entity { User, Post, Like, LikeCache }
5
+
import entity { Site, User, Post, Like, LikeCache }
6
6
7
7
////// Users //////
8
8
···
436
436
return ctx.ok('disliked post')
437
437
}
438
438
}
439
+
440
+
////// Site //////
441
+
442
+
@['/api/site/set_motd'; post]
443
+
fn (mut app App) api_site_set_motd(mut ctx Context, motd string) veb.Result {
444
+
user := app.whoami(mut ctx) or {
445
+
ctx.error('not logged in!')
446
+
return ctx.redirect('/login')
447
+
}
448
+
449
+
if user.admin {
450
+
sql app.db {
451
+
update Site set motd = motd where id == 1
452
+
} or {
453
+
ctx.error('failed to set motd')
454
+
eprintln('failed to set motd: ${motd}')
455
+
return ctx.redirect('/')
456
+
}
457
+
println('set motd to: ${motd}')
458
+
return ctx.redirect('/')
459
+
} else {
460
+
ctx.error('insufficient permissions!')
461
+
eprintln('insufficient perms to set motd to: ${motd} (${user.id})')
462
+
return ctx.redirect('/')
463
+
}
464
+
}
+25
-1
src/app.v
+25
-1
src/app.v
···
3
3
import veb
4
4
import db.pg
5
5
import auth
6
-
import entity { User, Post, Like, LikeCache }
6
+
import entity { Site, User, Post, Like, LikeCache }
7
7
8
8
pub struct App {
9
9
veb.StaticHandler
···
220
220
221
221
return likes
222
222
}
223
+
224
+
pub fn (app &App) get_or_create_site_config() Site {
225
+
configs := sql app.db {
226
+
select from entity.Site
227
+
} or { [] }
228
+
if configs.len == 0 {
229
+
// make the site config
230
+
site_config := entity.Site{ }
231
+
sql app.db {
232
+
insert site_config into entity.Site
233
+
} or {
234
+
panic('failed to create site config (${err})')
235
+
}
236
+
} else if configs.len > 1 {
237
+
// this should never happen
238
+
panic('there are multiple site configs')
239
+
}
240
+
return configs[0]
241
+
}
242
+
243
+
pub fn (app &App) get_motd() string {
244
+
site := app.get_or_create_site_config()
245
+
return site.motd
246
+
}
-1
src/entity/post.v
-1
src/entity/post.v
+7
src/entity/site.v
+7
src/entity/site.v
+7
-1
src/entity/user.v
+7
-1
src/entity/user.v
···
2
2
3
3
import time
4
4
5
-
@[json: 'user']
6
5
pub struct User {
7
6
pub mut:
8
7
id int @[primary; sql: serial]
···
32
31
pub fn (user User) get_theme() string {
33
32
return user.theme or { '' }
34
33
}
34
+
35
+
@[inline]
36
+
pub fn (user User) to_str_without_sensitive_data() string {
37
+
return user.str()
38
+
.replace(user.password, '*'.repeat(16))
39
+
.replace(user.password_salt, '*'.repeat(16))
40
+
}
+4
src/main.v
+4
src/main.v
···
8
8
9
9
fn init_db(db pg.DB) ! {
10
10
sql db {
11
+
create table entity.Site
11
12
create table entity.User
12
13
create table entity.Post
13
14
create table entity.Like
···
47
48
48
49
app.mount_static_folder_at(app.config.static_path, '/static')!
49
50
init_db(db)!
51
+
52
+
// make the website config, if it does not exist
53
+
app.get_or_create_site_config()
50
54
51
55
if config.dev_mode {
52
56
println('\033[1;31mNOTE: YOU ARE IN DEV MODE\033[0m')
+1
src/pages.v
+1
src/pages.v
+4
src/static/style.css
+4
src/static/style.css
+5
src/static/themes/catppuccin-macchiato-green.css
+5
src/static/themes/catppuccin-macchiato-green.css
+1
-59
src/static/themes/catppuccin-macchiato-pink.css
+1
-59
src/static/themes/catppuccin-macchiato-pink.css
···
1
-
@import url('https://cdn.jsdelivr.net/npm/water.css@2/out/dark.min.css');
2
-
@import url('https://unpkg.com/@catppuccin/palette/css/catppuccin.css');
1
+
@import url('/static/themes/catppuccin-macchiato.css');
3
2
4
3
:root {
5
4
--accent: var(--ctp-macchiato-pink);
6
-
7
-
--background-body: var(--ctp-macchiato-base);
8
-
--background: var(--ctp-macchiato-base);
9
-
--background-alt: var(--ctp-macchiato-crust);
10
-
--selection: var(--ctp-macchiato-overlay-2);
11
-
--text-main: var(--ctp-macchiato-text);
12
-
--text-bright: var(--ctp-macchiato-overlay-1);
13
-
--text-muted: var(--ctp-macchiato-subtext-0);
14
-
--links: var(--ctp-macchiato-blue);
15
-
--focus: var(--accent);
16
-
--border: var(--accent);
17
-
--code: var(--ctp-macchiato-text);
18
-
--button-hover: var(--ctp-macchiato-overlay-3);
19
-
--scrollbar-thumb: var(--accent);
20
-
--form-placeholder: var(--ctp-macchiato-overlay-1);
21
-
--form-text: var(--ctp-macchiato-text);
22
-
--variable: var(--ctp-macchiato-pink);
23
-
--highlight: var(--ctp-macchiato-blue);
24
-
--select-arrow: var(--accent);
25
-
}
26
-
27
-
input {
28
-
border: 1px solid var(--border);
29
-
margin-right: none;
30
-
width: calc(100% - 2px);
31
-
padding-right: 10px;
32
-
padding-left: 10px;
33
-
}
34
-
35
-
input[type="text"],
36
-
input[type="number"],
37
-
input[type="url"] {
38
-
width: calc(100% - 22px);
39
-
}
40
-
41
-
input[type="button"],
42
-
input[type="submit"] {
43
-
width: 100%;
44
-
}
45
-
46
-
textarea {
47
-
border: 1px solid var(--border);
48
-
width: 100%;
49
-
padding-right: 10px;
50
-
padding-left: 10px;
51
-
margin-right: none;
52
-
}
53
-
54
-
.post {
55
-
border: 1px solid var(--border);
56
-
width: calc(100% - 20px);
57
-
border-radius: 6px;
58
-
padding: 10px;
59
-
}
60
-
61
-
.post.post-full #id {
62
-
display: none;
63
5
}
+5
src/static/themes/catppuccin-macchiato-yellow.css
+5
src/static/themes/catppuccin-macchiato-yellow.css
+61
src/static/themes/catppuccin-macchiato.css
+61
src/static/themes/catppuccin-macchiato.css
···
1
+
@import url('https://cdn.jsdelivr.net/npm/water.css@2/out/dark.min.css');
2
+
@import url('https://unpkg.com/@catppuccin/palette/css/catppuccin.css');
3
+
4
+
:root {
5
+
--background-body: var(--ctp-macchiato-base);
6
+
--background: var(--ctp-macchiato-mantle);
7
+
--background-alt: var(--ctp-macchiato-crust);
8
+
--selection: var(--ctp-macchiato-overlay-2);
9
+
--text-main: var(--ctp-macchiato-text);
10
+
--text-bright: var(--ctp-macchiato-overlay-1);
11
+
--text-muted: var(--ctp-macchiato-subtext-0);
12
+
--links: var(--accent);
13
+
--focus: var(--accent);
14
+
--border: var(--accent);
15
+
--code: var(--ctp-macchiato-text);
16
+
--button-hover: var(--ctp-macchiato-mantle);
17
+
--scrollbar-thumb: var(--accent);
18
+
--form-placeholder: var(--ctp-macchiato-overlay-1);
19
+
--form-text: var(--ctp-macchiato-text);
20
+
--variable: var(--ctp-macchiato-pink);
21
+
--highlight: var(--ctp-macchiato-blue);
22
+
--select-arrow: var(--accent);
23
+
}
24
+
25
+
input {
26
+
border: 1px solid var(--border);
27
+
margin-right: none;
28
+
width: calc(100% - 2px);
29
+
padding-right: 10px;
30
+
padding-left: 10px;
31
+
}
32
+
33
+
input[type="text"],
34
+
input[type="number"],
35
+
input[type="url"] {
36
+
width: calc(100% - 22px);
37
+
}
38
+
39
+
input[type="button"],
40
+
input[type="submit"] {
41
+
width: 100%;
42
+
}
43
+
44
+
textarea {
45
+
border: 1px solid var(--border);
46
+
width: 100%;
47
+
padding-right: 10px;
48
+
padding-left: 10px;
49
+
margin-right: none;
50
+
}
51
+
52
+
.post {
53
+
border: 1px solid var(--border);
54
+
width: calc(100% - 20px);
55
+
border-radius: 6px;
56
+
padding: 10px;
57
+
}
58
+
59
+
.post.post-full #id {
60
+
display: none;
61
+
}
+15
src/static/themes/hackerman.css
+15
src/static/themes/hackerman.css
···
1
+
@import url('https://unpkg.com/simpledotcss/simple.min.css');
2
+
3
+
:root {
4
+
color-scheme: dark;
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;
14
+
--disabled: #333;
15
+
}
+15
-1
src/templates/admin.html
+15
-1
src/templates/admin.html
···
7
7
@else
8
8
9
9
<h1>admin dashboard</h1>
10
+
10
11
<p>logged in as:</p>
11
-
<pre>@user</pre>
12
+
<details>
13
+
<summary>show user details (<strong>SENSITIVE DATA IS CENSORED BUT FOR THE SAKE OF GOOD PRACTICE, DO NOT SHOW THIS DATA TO ANYONE</strong>)</summary>
14
+
<pre>@user.to_str_without_sensitive_data()</pre>
15
+
</details>
16
+
17
+
<div>
18
+
<h2>site settings:</h2>
19
+
<form action="/api/site/set_motd" method="post">
20
+
<label for="motd">message of the day (motd): </label>
21
+
<input type="text" name="motd" id="motd" value="@app.get_motd()">
22
+
<input type="submit" value="save">
23
+
</form>
24
+
</div>
25
+
12
26
<div>
13
27
<h2>user list:</h2>
14
28
<ul>