diff --git a/WIP.md b/WIP.md
index aabe8b8..2b0526d 100644
--- a/WIP.md
+++ b/WIP.md
@@ -4,24 +4,22 @@ for simplicity, I keep todo list and progress here for now
**Before release**:
- [ ] Review "TODO!"s
-- [ ] Homepage
+- [x] Homepage
- [ ] Licence
-- [ ] RELEASE
+- [x] RELEASE
---
-AFTER RELEASE CHECKLIST:
-- [x] Setup & test email
-- [x] Setup & test auth & registration with google
-- [x] Setup & test auth & registration with github
-- [x] Setup & test tracing
-- [ ] Enable linting and testing on CI/CD
-- [ ] Disable push to main without MR
+Tweaks & fixes:
+- [ ] Add description to upload book cover input
+- [ ] When book cover upload ends with error, another cannot be added
-NEXT:
+
+TODO:
- [ ] Resend verification link (Sometimes email is lost in somewhere between the woods (Not mailman to blame))
- [ ] Create new topic when creating/editing entity
- [ ] Pages
- [ ] Add meta to page (Who created, last edit by who and list of activities on page (api call))
+ - [ ] Content chips
- [ ] Books
- [ ] Add subtitle
- [ ] Sort
@@ -53,3 +51,4 @@ NEXT:
- [ ] Let user continue work on reject entity and proposed changes
- [ ] Review "delete account" test. Right now, it passes even if models belonging to the user still exist.
- [ ] Order of props when reviewing changes and public diffs should be constant and predefined
+- [ ] Sitemap
diff --git a/app/repo/page_repo.go b/app/repo/page_repo.go
index 81e49ff..fa936c8 100644
--- a/app/repo/page_repo.go
+++ b/app/repo/page_repo.go
@@ -30,6 +30,22 @@ func (r *Repo) GetPageByPublicID(ctx context.Context, publicID string) (*ds.Page
return page, err
}
+// GetPagesByPublicID retrieves pages by given public ID.
+func (r *Repo) GetPagesByPublicID(ctx context.Context, publicIDs ...string) (pages []ds.Page, err error) {
+ _, span := r.tracer.Start(ctx, "GetPageByPublicID")
+ defer span.End()
+
+ if len(publicIDs) == 0 {
+ return
+ }
+
+ pages = make([]ds.Page, 0, len(publicIDs))
+ const query = `SELECT * FROM entities e JOIN pages p USING (id) WHERE e.public_id = ANY($1) AND e.type = $2 AND e.deleted_at IS NULL`
+
+ err = pgxscan.Select(ctx, r.getDB(ctx), &pages, query, publicIDs, ds.EntityTypePage)
+ return
+}
+
// GetPageByID retrieves a page by its ID.
func (r *Repo) GetPageByID(ctx context.Context, id ds.ID) (*ds.Page, error) {
_, span := r.tracer.Start(ctx, "GetPageByID")
diff --git a/app/service/page_service.go b/app/service/page_service.go
index 5705952..31440c1 100644
--- a/app/service/page_service.go
+++ b/app/service/page_service.go
@@ -11,7 +11,7 @@ import (
"github.com/gopl-dev/server/email"
)
-// GetPageByPublicID retrieves a page by its public identifier.
+// GetPageByPublicID retrieves a page by its public ID.
func (s *Service) GetPageByPublicID(ctx context.Context, id string) (*ds.Page, error) {
ctx, span := s.tracer.Start(ctx, "GetPageByPublicID")
defer span.End()
@@ -19,6 +19,14 @@ func (s *Service) GetPageByPublicID(ctx context.Context, id string) (*ds.Page, e
return s.db.GetPageByPublicID(ctx, id)
}
+// GetPagesByPublicID retrieves pages by given public IDs.
+func (s *Service) GetPagesByPublicID(ctx context.Context, id ...string) ([]ds.Page, error) {
+ ctx, span := s.tracer.Start(ctx, "GetPagesByPublicID")
+ defer span.End()
+
+ return s.db.GetPagesByPublicID(ctx, id...)
+}
+
// GetPageByID retrieves a page by its ID from the database.
func (s *Service) GetPageByID(ctx context.Context, id ds.ID) (*ds.Page, error) {
ctx, span := s.tracer.Start(ctx, "GetBookByID")
diff --git a/frontend/assets/output.css b/frontend/assets/output.css
index e311cd3..38cd685 100644
--- a/frontend/assets/output.css
+++ b/frontend/assets/output.css
@@ -3590,9 +3590,6 @@
.left-0 {
left: calc(var(--spacing) * 0);
}
- .left-1 {
- left: calc(var(--spacing) * 1);
- }
.left-1\/2 {
left: calc(1/2 * 100%);
}
@@ -5151,6 +5148,9 @@
.mb-4 {
margin-bottom: calc(var(--spacing) * 4);
}
+ .mb-5 {
+ margin-bottom: calc(var(--spacing) * 5);
+ }
.mb-10 {
margin-bottom: calc(var(--spacing) * 10);
}
@@ -5920,15 +5920,9 @@
.w-6 {
width: calc(var(--spacing) * 6);
}
- .w-11 {
- width: calc(var(--spacing) * 11);
- }
.w-11\/12 {
width: calc(11/12 * 100%);
}
- .w-32 {
- width: calc(var(--spacing) * 32);
- }
.w-40 {
width: calc(var(--spacing) * 40);
}
@@ -5983,10 +5977,6 @@
.border-collapse {
border-collapse: collapse;
}
- .-translate-x-1 {
- --tw-translate-x: calc(var(--spacing) * -1);
- translate: var(--tw-translate-x) var(--tw-translate-y);
- }
.-translate-x-1\/2 {
--tw-translate-x: calc(calc(1/2 * 100%) * -1);
translate: var(--tw-translate-x) var(--tw-translate-y);
@@ -6195,9 +6185,6 @@
.gap-8 {
gap: calc(var(--spacing) * 8);
}
- .self-start {
- align-self: flex-start;
- }
.overflow-x-auto {
overflow-x: auto;
}
@@ -6628,9 +6615,6 @@
.border-info {
border-color: var(--color-info);
}
- .border-neutral-content {
- border-color: var(--color-neutral-content);
- }
.border-neutral-content\/30 {
border-color: var(--color-neutral-content);
@supports (color: color-mix(in lab, red, red)) {
@@ -7043,6 +7027,9 @@
.py-2 {
padding-block: calc(var(--spacing) * 2);
}
+ .py-4 {
+ padding-block: calc(var(--spacing) * 4);
+ }
.py-8 {
padding-block: calc(var(--spacing) * 8);
}
@@ -7055,9 +7042,6 @@
font-size: 1.375rem;
}
}
- .pt-1 {
- padding-top: calc(var(--spacing) * 1);
- }
.pt-6 {
padding-top: calc(var(--spacing) * 6);
}
@@ -8381,6 +8365,11 @@
width: auto;
}
}
+ .lg\:grid-cols-2 {
+ @media (width >= 64rem) {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+ }
.lg\:grid-cols-4 {
@media (width >= 64rem) {
grid-template-columns: repeat(4, minmax(0, 1fr));
diff --git a/frontend/component/form.templ b/frontend/component/form.templ
index 31aa157..6bd1feb 100644
--- a/frontend/component/form.templ
+++ b/frontend/component/form.templ
@@ -7,7 +7,7 @@ const (
const (
LabelClass = "text-gray-900"
InputClassDefault = "input input-xl w-full"
- TextareaClassDefault = "textarea textarea-xl w-full"
+ TextareaClassDefault = "textarea w-full"
InputClassError = "input-error"
)
diff --git a/frontend/component/form_templ.go b/frontend/component/form_templ.go
index 9c6d301..0ff1b20 100644
--- a/frontend/component/form_templ.go
+++ b/frontend/component/form_templ.go
@@ -15,7 +15,7 @@ const (
const (
LabelClass = "text-gray-900"
InputClassDefault = "input input-xl w-full"
- TextareaClassDefault = "textarea textarea-xl w-full"
+ TextareaClassDefault = "textarea w-full"
InputClassError = "input-error"
)
diff --git a/frontend/page/edit_page.templ b/frontend/page/edit_page.templ
index 55aeb98..c643a23 100644
--- a/frontend/page/edit_page.templ
+++ b/frontend/page/edit_page.templ
@@ -189,7 +189,7 @@ templ EditPageForm(pageID string) {
Model: "form.content",
ErrorModel: "errors.content",
Type: "textarea",
- Rows: 15,
+ Rows: 25,
Description: "You can use Markdown.",
})
diff --git a/frontend/page/edit_page_templ.go b/frontend/page/edit_page_templ.go
index 145d478..bb3a571 100644
--- a/frontend/page/edit_page_templ.go
+++ b/frontend/page/edit_page_templ.go
@@ -87,7 +87,7 @@ func EditPageForm(pageID string) templ.Component {
Model: "form.content",
ErrorModel: "errors.content",
Type: "textarea",
- Rows: 15,
+ Rows: 25,
Description: "You can use Markdown.",
}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
diff --git a/frontend/page/home.templ b/frontend/page/home.templ
index 1e0bbec..5ef4bb2 100644
--- a/frontend/page/home.templ
+++ b/frontend/page/home.templ
@@ -1,13 +1,74 @@
package page
-templ Home() {
-
-
hello world
-
-
-
-
+import "github.com/gopl-dev/server/frontend/component/icon"
+
+type HomeData struct {
+ Title string
+ Data map[string]string
+}
+
+templ Home(d HomeData) {
+
+
+
+ @templ.Raw(d.Data["intro"])
+
+
+
+
+
+ @templ.Raw(d.Data["getting-started"])
+
+
+
+
+
+ @templ.Raw(d.Data["tools"])
+
+
+
+
+
+ @templ.Raw(d.Data["community"])
+
}
diff --git a/frontend/page/home_templ.go b/frontend/page/home_templ.go
index cd89111..74b0da0 100644
--- a/frontend/page/home_templ.go
+++ b/frontend/page/home_templ.go
@@ -8,7 +8,14 @@ package page
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
-func Home() templ.Component {
+import "github.com/gopl-dev/server/frontend/component/icon"
+
+type HomeData struct {
+ Title string
+ Data map[string]string
+}
+
+func Home(d HomeData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -29,7 +36,84 @@ func Home() templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
hello world
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var2 string
+ templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(d.Title)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `frontend/page/home.templ`, Line: 14, Col: 21}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = icon.Pencil("w-4").Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ.Raw(d.Data["intro"]).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ.Raw(d.Data["getting-started"]).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ.Raw(d.Data["tools"]).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ.Raw(d.Data["community"]).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/frontend/page/view_page.templ b/frontend/page/view_page.templ
index 14c69f3..073f32f 100644
--- a/frontend/page/view_page.templ
+++ b/frontend/page/view_page.templ
@@ -3,13 +3,15 @@ package page
import "github.com/gopl-dev/server/frontend/component/icon"
templ ViewPage(id, title, text string) {
-
+
- @templ.Raw(text)
+
+ @templ.Raw(text)
+
}
diff --git a/frontend/page/view_page_templ.go b/frontend/page/view_page_templ.go
index 01c9ee8..18b4803 100644
--- a/frontend/page/view_page_templ.go
+++ b/frontend/page/view_page_templ.go
@@ -31,14 +31,14 @@ func ViewPage(id, title, text string) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `frontend/page/view_page.templ`, Line: 8, Col: 19}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `frontend/page/view_page.templ`, Line: 8, Col: 42}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -65,7 +65,7 @@ func ViewPage(id, title, text string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "Edit
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "Edit
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -73,7 +73,7 @@ func ViewPage(id, title, text string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/server/handler/dashboard_handler.go b/server/handler/dashboard_handler.go
index 7bbe733..89c5ee4 100644
--- a/server/handler/dashboard_handler.go
+++ b/server/handler/dashboard_handler.go
@@ -23,7 +23,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
renderTempl(ctx, w, layout.Dashboard(layout.Data{
Title: "Dashboard",
- Body: page.Home(),
+ Body: page.Home(page.HomeData{}),
User: frontend.NewUser(ds.UserFromContext(r.Context())),
}))
}
diff --git a/server/handler/home_handler.go b/server/handler/home_handler.go
index e2c4ad8..ff4bb5b 100644
--- a/server/handler/home_handler.go
+++ b/server/handler/home_handler.go
@@ -7,6 +7,7 @@ import (
"github.com/gopl-dev/server/frontend"
"github.com/gopl-dev/server/frontend/layout"
"github.com/gopl-dev/server/frontend/page"
+ "github.com/gopl-dev/server/test/factory/random"
)
// Home sweet home.
@@ -14,9 +15,45 @@ func (h *Handler) Home(w http.ResponseWriter, r *http.Request) {
ctx, span := h.tracer.Start(r.Context(), "Home")
defer span.End()
+ pages, err := h.service.GetPagesByPublicID(ctx,
+ "intro", "getting-started", "tools", "community",
+ )
+ if err != nil {
+ Abort(w, r, err)
+ return
+ }
+
+ data := page.HomeData{
+ Title: "Welcome",
+ Data: map[string]string{},
+ }
+
+ for _, p := range pages {
+ data.Data[p.PublicID] = p.Content
+ }
+
+ title := random.Element([]string{
+ // Now that you have found a list of silly titles, please read through it.
+ "Green Olives Party Late",
+ "Goats Organizing Pajama Launches",
+ "Grandma’s Overpowered Pancake Love",
+ "Galactic Octopus Pizza League",
+ "Giraffes On Purple Ladders",
+ "Goblin Operations & Potion Logistics",
+ "Grumpy Owls Playing Lute",
+ "Gravity Occasionally Pauses Lunch",
+ "Global Organization of Professional Llamas",
+ "Gigantic Overengineered Paperclip Lab",
+ // Thanks. Now that you have committed and if you want to continue, do this three steps:
+ // 1. remove one string from this list that you dislike
+ // 2. add two of your silly titles of your liking (that explain the acronym GOPL).
+ // 3. move this list elsewhere (within this repo, ofc)
+ })
+
+ data.Title = title
renderTempl(ctx, w, layout.Default(layout.Data{
- Title: "Welcome!",
- Body: page.Home(),
+ Title: "Welcome",
+ Body: page.Home(data),
User: frontend.NewUser(ds.UserFromContext(r.Context())),
}))
}