diff --git a/' b/' new file mode 100644 index 0000000..51d0fb6 --- /dev/null +++ b/' @@ -0,0 +1,130 @@ +body { + background: #EEF2FF; +} + +/* INDEX */ + +#clavis { + display: block; + width: 300px; + margin: 10px auto; + margin-bottom: 50px; +} + + +/* BOARD LIST */ + +#boardList { + font-size: 12px; + margin: 5px; +} + +#boardList a { + cursor: pointer; + color: #575F68; +} + +#boardList a:hover { + color: #ff0000; +} + +/* BOARDS */ + +.board-header { + text-align: center; + color: #AF0A0F; +} + +.board-header h1 { + font-weight: bold; + font-size: 1.8rem; + margin: 8px; + margin-top: 12px; +} + +.board-header p { + font-size: .8rem; + margin: 4px; +} + +.board-header img { + width: 300px; +} + +.new-thread-container { + width: max-content; + margin: auto; +} + +.thread-catalog-post { + border: 2px solid rgba(111, 111, 111, 0.34); + min-width: 140px; + max-width: 140px; + max-height: 192px; +} + +.thread-catalog-post h1 { + color: #0F0C5D; + font-weight: bold; +} + +.thread-catalog-post p { + margin-top: 10px; + font-size: 12px; +} + +#newThreadBtn { + margin-top: 12px; + background: none; + border: none; + padding: 0; + font-weight: bold; + font-size: 1.2rem; + color: #34345C; + cursor: pointer; +} + +#newThreadBtn:hover { + color: #ff0000 +} + +.new-thread-form-field {} + +.new-thread-form-field th { + border: 1px solid black; + text-align: left; + vertical-align: middle; + padding: 4px; + background: #98E; + font-weight: bold; + font-size: .8rem; +} + +.new-thread-form-field td { + display: block; + margin: 2px; +} + +/* GENERAL LAYOUT */ + +.container { + width: 600px; + margin: auto; +} + +.box { + font-size: 12px; + border: 1px solid black; + background-color: #eceff6; +} + +.box h2 { + padding: 5px; + margin: 0; + background-color: #00007F; + color: #FFF; +} + +.box p { + padding: 10px; +} diff --git a/internal/database/handlers.go b/internal/database/handlers.go index 4977867..d296916 100644 --- a/internal/database/handlers.go +++ b/internal/database/handlers.go @@ -32,3 +32,44 @@ func GetBoard(db *sql.DB, slug string) (Board, error) { return result, row.Err() } + +func GetBoardThreads(db *sql.DB, board_id int) ([]Thread, error) { + rows, err := db.Query( + `SELECT id, board_id, subject, created_at, bumped_at FROM threads WHERE board_id = ?`, board_id) + if err != nil { + return nil, err + } + defer rows.Close() + + var result []Thread + for rows.Next() { + var t Thread + err := rows.Scan(&t.Id, &t.BoardId, &t.Subject, &t.CreatedAt, &t.BumpedAt) + if err != nil { + return nil, err + } + result = append(result, t) + } + + return result, rows.Err() +} + +func GetThreadPosts(db *sql.DB, thread_id int) ([]Post, error) { + rows, err := db.Query(`SELECT id, thread_id, author, body, created_at FROM posts where thread_id = ?`, thread_id) + if err != nil { + return nil, err + } + defer rows.Close() + + var result []Post + for rows.Next() { + var p Post + err := rows.Scan(&p.Id, &p.ThreadId, &p.Author, &p.Body, &p.CreatedAt) + if err != nil { + return nil, err + } + result = append(result, p) + } + + return result, rows.Err() +} diff --git a/main.go b/main.go index 8d71cdd..5390436 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "net/http" + "strconv" "github.com/dominicf2001/comfychan/internal/database" "github.com/dominicf2001/comfychan/web/views" @@ -51,13 +52,46 @@ func main() { board, err := database.GetBoard(db, slug) if err != nil { http.NotFound(w, r) - log.Printf("board %q not found: %v", slug, err) + log.Printf("Board %q not found: %v", slug, err) return } views.Board(board).Render(r.Context(), w) }) + r.Get("/hx/{boardId}/posts/grid", func(w http.ResponseWriter, r *http.Request) { + boardIdStr := chi.URLParam(r, "boardId") + boardId, err := strconv.Atoi(boardIdStr) + if err != nil { + http.Error(w, "invalid board id", http.StatusBadRequest) + return + } + + threads, err := database.GetBoardThreads(db, boardId) + if err != nil { + http.Error(w, "Failed to get board threads", http.StatusInternalServerError) + log.Printf("GetBoardThreads: %v", err) + return + } + + vms := make([]views.ThreadGridBoxViewModel, 0, len(threads)) + for _, thread := range threads { + posts, err := database.GetThreadPosts(db, thread.Id) + if err != nil { + http.Error(w, "Error getting thread posts", http.StatusBadRequest) + log.Printf("GetThreadPosts: %v", err) + return + } + + vms = append(vms, views.ThreadGridBoxViewModel{ + Thread: thread, + Posts: posts, + }) + } + + views.PostsGrid(vms).Render(r.Context(), w) + }) + fmt.Println("Listening on :8080") http.ListenAndServe(":8080", r) } diff --git a/web/static/index.css b/web/static/index.css index 1975ee3..b95a808 100644 --- a/web/static/index.css +++ b/web/static/index.css @@ -56,6 +56,28 @@ body { margin: auto; } +#threadCatalog { + margin: 0 2rem; +} + +.thread-catalog-post { + padding: 10px; + border: 2px solid rgba(111, 111, 111, 0.34); + min-width: 140px; + max-width: 140px; + max-height: 192px; +} + +.thread-catalog-post h1 { + color: #0F0C5D; + font-weight: bold; +} + +.thread-catalog-post p { + margin-top: 10px; + font-size: 12px; +} + #newThreadBtn { margin-top: 12px; background: none; diff --git a/web/views/board.templ b/web/views/board.templ index 36ca680..3f995be 100644 --- a/web/views/board.templ +++ b/web/views/board.templ @@ -1,42 +1,43 @@ package views import ( - "fmt" - database "github.com/dominicf2001/comfychan/internal/database" - "github.com/dominicf2001/comfychan/web/views/shared" +"fmt" +database "github.com/dominicf2001/comfychan/internal/database" +"github.com/dominicf2001/comfychan/web/views/shared" ) templ NewThreadForm() { - + } templ Board(board database.Board) { - @shared.Layout() { -
- -

- { fmt.Sprintf("/%s/ - %s", board.Slug, board.Name) } -

-

{ board.Tag }

-
-
- - @NewThreadForm() -
- } +@shared.Layout() { +
+ +

+ { fmt.Sprintf("/%s/ - %s", board.Slug, board.Name) } +

+

{ board.Tag }

+
+
+ + @NewThreadForm() +
+
+} } diff --git a/web/views/posts.templ b/web/views/posts.templ new file mode 100644 index 0000000..40b1af1 --- /dev/null +++ b/web/views/posts.templ @@ -0,0 +1,17 @@ +package views + +import "github.com/dominicf2001/comfychan/internal/database" + +type ThreadGridBoxViewModel struct { +Thread database.Thread +Posts []database.Post +} + +templ PostsGrid(vms []ThreadGridBoxViewModel) { +for _, vm := range vms { +
+

{ vm.Thread.Subject }

+

{ vm.Posts[0].Body }

+
+} +} diff --git a/web/views/shared/layout.templ b/web/views/shared/layout.templ index 262a7c0..e142551 100644 --- a/web/views/shared/layout.templ +++ b/web/views/shared/layout.templ @@ -1,33 +1,31 @@ package shared templ Layout() { - - - - - - Comfychan - - - - - - -
- - [ - index - ] - - - [ - comfy / - g - ] - -
- { children... } - - - + + + + + Comfychan + + + + + + +
+ + [ + index + ] + + + [ + comfy / + g + ] + +
+ { children... } + + }