diff --git a/assets/dk.css b/assets/dk.css index 4fce2c3..21d7ed5 100644 --- a/assets/dk.css +++ b/assets/dk.css @@ -272,6 +272,33 @@ form.standard { background-color: rgba(0, 0, 0, 0.6); border-color: black; } + + &::placeholder { + color: rgba(255, 255, 255, 0.6); + } + } + + textarea.forum-text { + appearance: none; + outline: none; + border: 1px solid transparent; + padding: 0.25rem 0.25rem; + background-color: rgba(0, 0, 0, 0.4); + color: white; + min-height: 200px; + + &:hover { + background-color: rgba(0, 0, 0, 0.5); + } + + &:focus { + background-color: rgba(0, 0, 0, 0.6); + border-color: black; + } + + &::placeholder { + color: rgba(255, 255, 255, 0.6); + } } } @@ -287,6 +314,10 @@ form.standard { margin-bottom: 0.25rem; } +.w-full { + width: 100%; +} + div.town { & > section:not(:last-child) { margin-bottom: 2rem; @@ -494,3 +525,9 @@ div#battle-window { color: white; } } + +div.thread-title { + display: flex; + align-items: center; + justify-content: space-between; +} \ No newline at end of file diff --git a/data/dk.db b/data/dk.db index 1b4044d..598bc56 100644 Binary files a/data/dk.db and b/data/dk.db differ diff --git a/internal/models/forum/forum.go b/internal/models/forum/forum.go index 985e1db..81fb54a 100644 --- a/internal/models/forum/forum.go +++ b/internal/models/forum/forum.go @@ -83,13 +83,13 @@ func Find(id int) (*Forum, error) { func All() ([]*Forum, error) { var forums []*Forum - err := database.Select(&forums, "SELECT * FROM forum ORDER BY newpostdate DESC, id DESC") + err := database.Select(&forums, "SELECT * FROM forum ORDER BY last_post DESC, id DESC") return forums, err } func Threads() ([]*Forum, error) { var forums []*Forum - err := database.Select(&forums, "SELECT * FROM forum WHERE parent = 0 ORDER BY newpostdate DESC, id DESC") + err := database.Select(&forums, "SELECT * FROM forum WHERE parent = 0 ORDER BY last_post DESC, id DESC") return forums, err } @@ -97,37 +97,37 @@ func ByParent(parentID int) ([]*Forum, error) { var forums []*Forum if parentID > 0 { // Replies sorted chronologically - err := database.Select(&forums, "SELECT * FROM forum WHERE parent = %d ORDER BY postdate ASC, id ASC", parentID) + err := database.Select(&forums, "SELECT * FROM forum WHERE parent = %d ORDER BY posted ASC, id ASC", parentID) return forums, err } else { // Threads sorted by last activity - err := database.Select(&forums, "SELECT * FROM forum WHERE parent = %d ORDER BY newpostdate DESC, id DESC", parentID) + err := database.Select(&forums, "SELECT * FROM forum WHERE parent = %d ORDER BY last_post DESC, id DESC", parentID) return forums, err } } func ByAuthor(authorID int) ([]*Forum, error) { var forums []*Forum - err := database.Select(&forums, "SELECT * FROM forum WHERE author = %d ORDER BY postdate DESC, id DESC", authorID) + err := database.Select(&forums, "SELECT * FROM forum WHERE author = %d ORDER BY posted DESC, id DESC", authorID) return forums, err } func Recent(limit int) ([]*Forum, error) { var forums []*Forum - err := database.Select(&forums, "SELECT * FROM forum ORDER BY newpostdate DESC, id DESC LIMIT %d", limit) + err := database.Select(&forums, "SELECT * FROM forum ORDER BY last_post DESC, id DESC LIMIT %d", limit) return forums, err } func Search(term string) ([]*Forum, error) { var forums []*Forum searchTerm := "%" + term + "%" - err := database.Select(&forums, "SELECT * FROM forum WHERE title LIKE %s OR content LIKE %s ORDER BY newpostdate DESC, id DESC", searchTerm, searchTerm) + err := database.Select(&forums, "SELECT * FROM forum WHERE title LIKE %s OR content LIKE %s ORDER BY last_post DESC, id DESC", searchTerm, searchTerm) return forums, err } func Since(since int64) ([]*Forum, error) { var forums []*Forum - err := database.Select(&forums, "SELECT * FROM forum WHERE newpostdate >= %d ORDER BY newpostdate DESC, id DESC", since) + err := database.Select(&forums, "SELECT * FROM forum WHERE last_post >= %d ORDER BY last_post DESC, id DESC", since) return forums, err } diff --git a/internal/routes/forum.go b/internal/routes/forum.go index 3b35016..337d0a3 100644 --- a/internal/routes/forum.go +++ b/internal/routes/forum.go @@ -2,6 +2,11 @@ package routes import ( "dk/internal/components" + "dk/internal/database" + "dk/internal/models/forum" + "dk/internal/models/users" + "fmt" + "strings" sushi "git.sharkk.net/Sharkk/Sushi" "git.sharkk.net/Sharkk/Sushi/auth" @@ -11,8 +16,77 @@ func RegisterForumRoutes(app *sushi.App) { authed := app.Group("/forum") authed.Use(auth.RequireAuth()) authed.Get("/", index) + authed.Get("/new", showNew) + authed.Post("/new", new) + authed.Get("/:id", showThread) } func index(ctx sushi.Ctx) { - components.RenderPage(ctx, "Forum", "forum/index.html", map[string]any{}) + threads, err := forum.Threads() + if err != nil { + threads = make([]*forum.Forum, 0) + } + fmt.Printf("\nFound %d threads\n", len(threads)) + + components.RenderPage(ctx, "Forum", "forum/index.html", map[string]any{ + "threads": threads, + }) +} + +func showNew(ctx sushi.Ctx) { + components.RenderPage(ctx, "New Forum Thread", "forum/new.html", map[string]any{}) +} + +func new(ctx sushi.Ctx) { + sess := ctx.GetCurrentSession() + + title := strings.TrimSpace(ctx.Form("title").String()) + content := strings.TrimSpace(ctx.Form("content").String()) + + if title == "" { + sess.SetFlash("error", "Thread title cannot be empty") + ctx.Redirect("/forum/new") + return + } + + if content == "" { + sess.SetFlash("error", "Thread content cannot be empty") + ctx.Redirect("/forum/new") + return + } + + user := ctx.GetCurrentUser().(*users.User) + + thread := forum.New() + thread.Author = user.ID + thread.Title = title + thread.Content = content + + database.Transaction(func() error { + return thread.Insert() + }) + + ctx.Redirect(fmt.Sprintf("/forum/%d", thread.ID)) +} + +func showThread(ctx sushi.Ctx) { + sess := ctx.GetCurrentSession() + id := ctx.Param("id").Int() + + thread, err := forum.Find(id) + if err != nil { + sess.SetFlash("error", fmt.Sprintf("Forum thread %d not found", id)) + ctx.Redirect("/forum") + return + } + + if thread.Parent != 0 { + sess.SetFlash("error", fmt.Sprintf("Forum post %d is not a thread", id)) + ctx.Redirect("/forum") + return + } + + components.RenderPage(ctx, thread.Title, "forum/thread.html", map[string]any{ + "thread": thread, + }) } diff --git a/templates/forum/index.html b/templates/forum/index.html index 21c8ea0..578052e 100644 --- a/templates/forum/index.html +++ b/templates/forum/index.html @@ -1,5 +1,27 @@ {include "layout.html"} {block "content"} -FORUM PAGE +
+

Forum

+ +
+ +
+
+ + +{if #threads > 0} + + + {for thread in threads} + + + + + {/for} + +
{thread.Title}{thread.Replies} Replies
+{else} +No threads! +{/if} {/block} diff --git a/templates/forum/new.html b/templates/forum/new.html new file mode 100644 index 0000000..10907d7 --- /dev/null +++ b/templates/forum/new.html @@ -0,0 +1,19 @@ +{include "layout.html"} + +{block "content"} +

Forum

+ +
+ {csrf} + +
+
+ +
+ +
+ + +
+
+{/block} diff --git a/templates/forum/thread.html b/templates/forum/thread.html new file mode 100644 index 0000000..342745c --- /dev/null +++ b/templates/forum/thread.html @@ -0,0 +1,17 @@ +{include "layout.html"} + +{block "content"} +
+

{thread.Title}

+ +
+ + +
+
+ + +

+ {thread.Content} +

+{/block}