diff --git a/cmd/web/handlers.go b/cmd/web/handlers.go index bf3d2f1..abfdeaf 100644 --- a/cmd/web/handlers.go +++ b/cmd/web/handlers.go @@ -5,57 +5,49 @@ import ( "fmt" "net/http" + "git.32bit.cafe/32bitcafe/guestbook/internal/forms" "git.32bit.cafe/32bitcafe/guestbook/internal/models" "git.32bit.cafe/32bitcafe/guestbook/internal/validator" + "git.32bit.cafe/32bitcafe/guestbook/ui/views" ) func (app *application) home(w http.ResponseWriter, r *http.Request) { - data := app.newTemplateData(r) - app.render(w, r, http.StatusOK, "home.tmpl.html", data) -} - -type userRegistrationForm struct { - Name string `schema:"username"` - Email string `schema:"email"` - Password string `schema:"password"` - validator.Validator `schema:"-"` + data := app.newCommonData(r) + views.Home("Home", data).Render(r.Context(), w) } func (app *application) getUserRegister(w http.ResponseWriter, r *http.Request) { - data := app.newTemplateData(r) - data.Form = userRegistrationForm{} - app.render(w, r, http.StatusOK, "usercreate.view.tmpl.html", data) + form := forms.UserRegistrationForm{} + data := app.newCommonData(r) + views.UserRegistration("User Registration", data, form).Render(r.Context(), w) } func (app *application) postUserRegister(w http.ResponseWriter, r *http.Request) { - var form userRegistrationForm + var form forms.UserRegistrationForm err := app.decodePostForm(r, &form) if err != nil { app.clientError(w, http.StatusBadRequest) return } - form.CheckField(validator.NotBlank(form.Name), "name", "This field cannot be blank") form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank") form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address") form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank") form.CheckField(validator.MinChars(form.Password, 8), "password", "This field must be at least 8 characters long") - if !form.Valid() { - data := app.newTemplateData(r) - data.Form = form - app.render(w, r, http.StatusUnprocessableEntity, "usercreate.view.tmpl.html", data) + data := app.newCommonData(r) + w.WriteHeader(http.StatusUnprocessableEntity) + views.UserRegistration("User Registration", data, form).Render(r.Context(), w) return } - shortId := app.createShortId() err = app.users.Insert(shortId, form.Name, form.Email, form.Password) if err != nil { if errors.Is(err, models.ErrDuplicateEmail) { form.AddFieldError("email", "Email address is already in use") - data := app.newTemplateData(r) - data.Form = form - app.render(w ,r, http.StatusUnprocessableEntity, "usercreate.view.tmpl.html", data) + data := app.newCommonData(r) + w.WriteHeader(http.StatusUnprocessableEntity) + views.UserRegistration("User Registration", data, form).Render(r.Context(), w) } else { app.serverError(w, r, err) } @@ -65,58 +57,42 @@ func (app *application) postUserRegister(w http.ResponseWriter, r *http.Request) http.Redirect(w, r, "/users/login", http.StatusSeeOther) } -type userLoginForm struct { - Email string `schema:"email"` - Password string `schema:"password"` - validator.Validator `schema:"-"` -} - func (app *application) getUserLogin(w http.ResponseWriter, r *http.Request) { - data := app.newTemplateData(r) - data.Form = userLoginForm{} - app.render(w, r, http.StatusOK, "login.view.tmpl.html", data) + views.UserLogin("Login", app.newCommonData(r), forms.UserLoginForm{}).Render(r.Context(), w) } func (app *application) postUserLogin(w http.ResponseWriter, r *http.Request) { - var form userLoginForm - + var form forms.UserLoginForm err := app.decodePostForm(r, &form) if err != nil { app.clientError(w, http.StatusBadRequest) } - form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank") form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address") form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank") - if !form.Valid() { - data := app.newTemplateData(r) - data.Form = userLoginForm{} - app.render(w, r, http.StatusUnprocessableEntity, "login.view.tmpl.html", data) + data := app.newCommonData(r) + w.WriteHeader(http.StatusUnprocessableEntity) + views.UserLogin("Login", data, form).Render(r.Context(), w) return } - id, err := app.users.Authenticate(form.Email, form.Password) if err != nil { if errors.Is(err, models.ErrInvalidCredentials) { form.AddNonFieldError("Email or password is incorrect") - data := app.newTemplateData(r) - data.Form = form - app.render(w, r, http.StatusUnprocessableEntity, "login.view.tmpl.html", data) + data := app.newCommonData(r) + views.UserLogin("Login", data, form).Render(r.Context(), w) } else { app.serverError(w, r, err) } return } - err = app.sessionManager.RenewToken(r.Context()) if err != nil { app.serverError(w, r, err) return } - app.sessionManager.Put(r.Context(), "authenticatedUserId", id) - http.Redirect(w, r, "/", http.StatusSeeOther) } @@ -126,13 +102,14 @@ func (app *application) postUserLogout(w http.ResponseWriter, r *http.Request) { app.serverError(w, r, err) return } - app.sessionManager.Remove(r.Context(), "authenticatedUserId") app.sessionManager.Put(r.Context(), "flash", "You've been logged out successfully!") http.Redirect(w, r, "/", http.StatusSeeOther) } func (app *application) getUsersList(w http.ResponseWriter, r *http.Request) { + // skip templ conversion for this view, which will not be available in the final app + // something similar will be available in the admin panel users, err := app.users.GetAll() if err != nil { app.serverError(w, r, err) @@ -154,18 +131,13 @@ func (app *application) getUser(w http.ResponseWriter, r *http.Request) { } return } - data := app.newTemplateData(r) - data.User = user - app.render(w, r, http.StatusOK, "user.view.tmpl.html", data) + data := app.newCommonData(r) + views.UserProfile(user.Username, data, user).Render(r.Context(), w) } func (app *application) getGuestbookCreate(w http.ResponseWriter, r* http.Request) { - data := app.newTemplateData(r) - if r.Header.Get("HX-Request") == "true" { - app.renderHTMX(w, r, http.StatusOK, "guestbookcreate.part.html", data) - return - } - app.render(w, r, http.StatusOK, "guestbookcreate.view.tmpl.html", data) + data := app.newCommonData(r) + views.GuestbookCreate("New Guestbook", data).Render(r.Context(), w) } func (app *application) postGuestbookCreate(w http.ResponseWriter, r* http.Request) { @@ -194,24 +166,13 @@ func (app *application) postGuestbookCreate(w http.ResponseWriter, r* http.Reque func (app *application) getGuestbookList(w http.ResponseWriter, r *http.Request) { userId := app.sessionManager.GetInt64(r.Context(), "authenticatedUserId") - user, err := app.users.GetById(userId) - if err != nil { - app.serverError(w, r, err) - return - } guestbooks, err := app.guestbooks.GetAll(userId) if err != nil { app.serverError(w, r, err) return } - data := app.newTemplateData(r) - data.Guestbooks = guestbooks - data.User = user - if r.Header.Get("HX-Request") == "true" { - app.renderHTMX(w, r, http.StatusCreated, "guestbooklist.part.html", data) - return - } - app.render(w, r, http.StatusOK, "guestbooklist.view.tmpl.html", data) + data := app.newCommonData(r) + views.GuestbookList("Guestbooks", data, guestbooks).Render(r.Context(), w) } func (app *application) getGuestbook(w http.ResponseWriter, r *http.Request) { @@ -230,10 +191,8 @@ func (app *application) getGuestbook(w http.ResponseWriter, r *http.Request) { app.serverError(w, r, err) return } - data := app.newTemplateData(r) - data.Guestbook = guestbook - data.Comments = comments - app.render(w, r, http.StatusOK, "guestbook.view.tmpl.html", data) + data := app.newCommonData(r) + views.GuestbookView("Guestbook", data, guestbook, comments).Render(r.Context(), w) } func (app *application) getGuestbookComments(w http.ResponseWriter, r *http.Request) { @@ -267,6 +226,7 @@ type commentCreateForm struct { } func (app *application) getGuestbookCommentCreate(w http.ResponseWriter, r *http.Request) { + // TODO: This will be the embeddable form slug := r.PathValue("id") guestbook, err := app.guestbooks.Get(slugToShortId(slug)) if err != nil { @@ -324,7 +284,7 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt app.serverError(w, r, err) return } - app.sessionManager.Put(r.Context(), "flash", "Comment successfully posted!") + // app.sessionManager.Put(r.Context(), "flash", "Comment successfully posted!") http.Redirect(w, r, fmt.Sprintf("/guestbooks/%s", guestbookSlug), http.StatusSeeOther) } diff --git a/cmd/web/helpers.go b/cmd/web/helpers.go index ee17b06..e19001c 100644 --- a/cmd/web/helpers.go +++ b/cmd/web/helpers.go @@ -41,6 +41,21 @@ func (app *application) renderHTMX(w http.ResponseWriter, r *http.Request, statu } } +func (app *application) renderFullPage(w http.ResponseWriter, r *http.Request, status int, page string, data templateData) { + ts, ok := app.templateCache[page] + if !ok { + err := fmt.Errorf("the template %s does not exist", page) + app.serverError(w, r, err) + return + } + + w.WriteHeader(status) + err := ts.ExecuteTemplate(w, "base", data) + if err != nil { + app.serverError(w, r, err) + } +} + func (app *application) render(w http.ResponseWriter, r *http.Request, status int, page string, data templateData) { ts, ok := app.templateCache[page] if !ok { diff --git a/cmd/web/routes.go b/cmd/web/routes.go index aa21e1c..9276e78 100644 --- a/cmd/web/routes.go +++ b/cmd/web/routes.go @@ -12,9 +12,10 @@ func (app *application) routes() http.Handler { mux.Handle("GET /static/", http.StripPrefix("/static", fileServer)) dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf, app.authenticate) + standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders) mux.Handle("/{$}", dynamic.ThenFunc(app.home)) - mux.Handle("POST /guestbooks/{id}/comments/create", dynamic.ThenFunc(app.postGuestbookCommentCreate)) + mux.Handle("POST /guestbooks/{id}/comments/create", standard.ThenFunc(app.postGuestbookCommentCreate)) mux.Handle("GET /guestbooks/{id}", dynamic.ThenFunc(app.getGuestbook)) mux.Handle("GET /users/register", dynamic.ThenFunc(app.getUserRegister)) mux.Handle("POST /users/register", dynamic.ThenFunc(app.postUserRegister)) @@ -31,7 +32,6 @@ func (app *application) routes() http.Handler { mux.Handle("POST /guestbooks/create", protected.ThenFunc(app.postGuestbookCreate)) mux.Handle("GET /guestbooks/{id}/comments/create", protected.ThenFunc(app.getGuestbookCommentCreate)) - standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders) return standard.Then(mux) } diff --git a/cmd/web/templates.go b/cmd/web/templates.go index 0eb75bb..7d2908b 100644 --- a/cmd/web/templates.go +++ b/cmd/web/templates.go @@ -7,6 +7,7 @@ import ( "time" "git.32bit.cafe/32bitcafe/guestbook/internal/models" + "git.32bit.cafe/32bitcafe/guestbook/ui/views" "github.com/justinas/nosurf" ) @@ -77,6 +78,17 @@ func newTemplateCache() (map[string]*template.Template, error) { return cache, nil } +func (app *application) newCommonData(r *http.Request) views.CommonData { + return views.CommonData { + CurrentYear: time.Now().Year(), + Flash: app.sessionManager.PopString(r.Context(), "flash"), + IsAuthenticated: app.isAuthenticated(r), + CSRFToken: nosurf.Token(r), + CurrentUser: app.getCurrentUser(r), + IsHtmx: r.Header.Get("Hx-Request") == "true", + } +} + func (app *application) newTemplateData(r *http.Request) templateData { return templateData { CurrentYear: time.Now().Year(), diff --git a/go.mod b/go.mod index 56e429d..f710d94 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + github.com/a-h/templ v0.3.833 // indirect github.com/gorilla/schema v1.4.1 // indirect github.com/justinas/alice v1.2.0 // indirect github.com/justinas/nosurf v1.1.1 // indirect diff --git a/go.sum b/go.sum index 179b0b7..89cc066 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/a-h/templ v0.3.833 h1:L/KOk/0VvVTBegtE0fp2RJQiBm7/52Zxv5fqlEHiQUU= +github.com/a-h/templ v0.3.833/go.mod h1:cAu4AiZhtJfBjMY0HASlyzvkrtjnHWPeEsyGK2YYmfk= github.com/alexedwards/scs/sqlite3store v0.0.0-20240316134038-7e11d57e8885 h1:+DCxWg/ojncqS+TGAuRUoV7OfG/S4doh0pcpAwEcow0= github.com/alexedwards/scs/sqlite3store v0.0.0-20240316134038-7e11d57e8885/go.mod h1:Iyk7S76cxGaiEX/mSYmTZzYehp4KfyylcLaV3OnToss= github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw= diff --git a/internal/forms/forms.go b/internal/forms/forms.go new file mode 100644 index 0000000..36ebe28 --- /dev/null +++ b/internal/forms/forms.go @@ -0,0 +1,17 @@ +package forms + +import "git.32bit.cafe/32bitcafe/guestbook/internal/validator" + +type UserRegistrationForm struct { + Name string `schema:"username"` + Email string `schema:"email"` + Password string `schema:"password"` + validator.Validator `schema:"-"` +} + +type UserLoginForm struct { + Email string `schema:"email"` + Password string `schema:"password"` + validator.Validator `schema:"-"` +} + diff --git a/internal/models/guestbook.go b/internal/models/guestbook.go index 9e55936..618bdd8 100644 --- a/internal/models/guestbook.go +++ b/internal/models/guestbook.go @@ -2,6 +2,7 @@ package models import ( "database/sql" + "strconv" "time" ) @@ -15,6 +16,10 @@ type Guestbook struct { IsActive bool } +func (gb Guestbook) Slug() string { + return strconv.FormatUint(gb.ShortId, 36) +} + type GuestbookModel struct { DB *sql.DB } diff --git a/ui/static/css/style.css b/ui/static/css/style.css index b0f123e..140e874 100644 --- a/ui/static/css/style.css +++ b/ui/static/css/style.css @@ -1,511 +1,78 @@ -/* Set the global variables for everything. Change these to use your own fonts and colours. */ -:root { - /* Set sans-serif & mono fonts */ - --sans-font: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir, - "Nimbus Sans L", Roboto, Noto, "Segoe UI", Arial, Helvetica, - "Helvetica Neue", sans-serif; - --mono-font: Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace; - - /* Body font size. By default, effectively 18.4px, based on 16px as 'root em' */ - --base-fontsize: 1.15rem; - - /* Major third scale progression - see https://type-scale.com/ */ - --header-scale: 1.25; - - /* Line height is set to the "Golden ratio" for optimal legibility */ - --line-height: 1.618; - - /* Default (light) theme */ - --bg: #fff; - --accent-bg: #f5f7ff; - --text: #212121; - --text-light: #585858; - --border: #d8dae1; - --accent: #0d47a1; - --accent-light: #90caf9; - --code: #d81b60; - --preformatted: #444; - --marked: #ffdd33; - --disabled: #efefef; -} - -/* Dark theme */ -@media (prefers-color-scheme: dark) { - :root { - --bg: #212121; - --accent-bg: #2b2b2b; - --text: #dcdcdc; - --text-light: #ababab; - --border: #666; - --accent: #ffb300; - --accent-light: #ffecb3; - --code: #f06292; - --preformatted: #ccc; - --disabled: #111; - } - - img, - video { - opacity: 0.6; - } -} - html { - /* Set the font globally */ - font-family: var(--sans-font); + background: lightgray; } -/* Make the body a nice central block */ body { - color: var(--text); - background: var(--bg); - font-size: var(--base-fontsize); - line-height: var(--line-height); - display: flex; - min-height: 100vh; - flex-direction: column; - flex: 1; - margin: 0 auto; - max-width: 45rem; - padding: 0 0.5rem; - overflow-x: hidden; - word-break: break-word; - overflow-wrap: break-word; + max-width: 1024px; + margin: 1rem auto; + padding: 1rem; + background: white; + font-size: 1.2rem; + line-height: 1.5; + font-family: Arial, Helvetica, sans-serif; } -/* Make the header bg full width, but the content inline with body */ header { - background: var(--accent-bg); - border-bottom: 1px solid var(--border); text-align: center; - padding: 2rem 0.5rem; - width: 100vw; - position: relative; - box-sizing: border-box; - left: 50%; - right: 50%; - margin-left: -50vw; - margin-right: -50vw; } -/* Remove margins for header text */ -header h1, -header p { - margin: 0; +body > nav { + display: flex; + justify-content: space-between; } -/* Add a little padding to ensure spacing is correct between content and nav */ -main { - padding-top: 1.5rem; +body > nav ul { + list-style: none; + margin: 0 1rem; + padding: 0; } -/* Fix line height when title wraps */ -h1, -h2, -h3 { - line-height: 1.1; -} - -/* Format navigation */ -nav { - font-size: 1rem; - line-height: 2; - padding: 1rem 0; -} - -nav a { - margin: 1rem 1rem 0 0; - border: 1px solid var(--border); - border-radius: 5px; - color: var(--text) !important; +body > nav li { display: inline-block; - padding: 0.1rem 1rem; - text-decoration: none; - transition: 0.4s; + padding: 0 0.5rem; } -nav a:hover { - color: var(--accent) !important; - border-color: var(--accent); +nav form { + display: inline-block; } -nav a.current:hover { - text-decoration: none; +nav button { + border: none; + background: none; + font-family: unset; + font-size: unset; + color: blue; + text-decoration: underline; + cursor: pointer; +} + +main { + padding: 1rem; +} + +div#main { + display: flex; + flex-flow: row wrap; +} + +div#main nav { + flex: 1 1 25%; +} + +div#main > div { + flex: 10 1 40%; +} + +main nav ul { + list-style: none; + margin: 1rem; + padding: 0; } footer { - margin-top: 4rem; - padding: 2rem 1rem 1.5rem 1rem; - color: var(--text-light); - font-size: 0.9rem; text-align: center; - border-top: 1px solid var(--border); } -/* Format headers */ -h1 { - font-size: calc( - var(--base-fontsize) * var(--header-scale) * var(--header-scale) * - var(--header-scale) * var(--header-scale) - ); - margin-top: calc(var(--line-height) * 1.5rem); -} - -h2 { - font-size: calc( - var(--base-fontsize) * var(--header-scale) * var(--header-scale) * - var(--header-scale) - ); - margin-top: calc(var(--line-height) * 1.5rem); -} - -h3 { - font-size: calc( - var(--base-fontsize) * var(--header-scale) * var(--header-scale) - ); - margin-top: calc(var(--line-height) * 1.5rem); -} - -h4 { - font-size: calc(var(--base-fontsize) * var(--header-scale)); - margin-top: calc(var(--line-height) * 1.5rem); -} - -h5 { - font-size: var(--base-fontsize); - margin-top: calc(var(--line-height) * 1.5rem); -} - -h6 { - font-size: calc(var(--base-fontsize) / var(--header-scale)); - margin-top: calc(var(--line-height) * 1.5rem); -} - -/* Format links & buttons */ -a, -a:visited { - color: var(--accent); -} - -a:hover { - text-decoration: none; -} - -a button, -button, -[role="button"], -input[type="submit"], -input[type="reset"], -input[type="button"] { - border: none; - border-radius: 5px; - background: var(--accent); - font-size: 1rem; - color: var(--bg); - padding: 0.7rem 0.9rem; - margin: 0.5rem 0; - transition: 0.4s; -} - -a button[disabled], -button[disabled], -[role="button"][aria-disabled="true"], -input[type="submit"][disabled], -input[type="reset"][disabled], -input[type="button"][disabled], -input[type="checkbox"][disabled], -input[type="radio"][disabled], -select[disabled] { - cursor: default; - opacity: 0.5; - cursor: not-allowed; -} - -input:disabled, -textarea:disabled, -select:disabled { - cursor: not-allowed; - background-color: var(--disabled); -} - -input[type="range"] { - padding: 0; -} - -/* Set the cursor to '?' while hovering over an abbreviation */ -abbr { - cursor: help; -} - -button:focus, -button:enabled:hover, -[role="button"]:focus, -[role="button"]:not([aria-disabled="true"]):hover, -input[type="submit"]:focus, -input[type="submit"]:enabled:hover, -input[type="reset"]:focus, -input[type="reset"]:enabled:hover, -input[type="button"]:focus, -input[type="button"]:enabled:hover, -input[type="checkbox"]:focus, -input[type="checkbox"]:enabled:hover, -input[type="radio"]:focus, -input[type="radio"]:enabled:hover { - filter: brightness(1.4); - cursor: pointer; -} - -/* Format the expanding box */ -details { - background: var(--accent-bg); - border: 1px solid var(--border); - border-radius: 5px; - margin-bottom: 1rem; -} - -summary { - cursor: pointer; - font-weight: bold; - padding: 0.6rem 1rem; -} - -details[open] { - padding: 0.6rem 1rem 0.75rem 1rem; -} - -details[open] summary { - margin-bottom: 0.5rem; - padding: 0; -} - -details[open] > *:last-child { - margin-bottom: 0; -} - -/* Format tables */ -table { - border-collapse: collapse; - width: 100%; - margin: 1.5rem 0; -} - -td, -th { - border: 1px solid var(--border); - text-align: left; - padding: 0.5rem; -} - -th { - background: var(--accent-bg); - font-weight: bold; -} - -tr:nth-child(even) { - /* Set every other cell slightly darker. Improves readability. */ - background: var(--accent-bg); -} - -table caption { - font-weight: bold; - margin-bottom: 0.5rem; -} - -/* Lists */ -ol, -ul { - padding-left: 3rem; -} - -/* Format forms */ -textarea, -select, -input { - font-size: inherit; - font-family: inherit; - padding: 0.5rem; - margin-bottom: 0.5rem; - color: var(--text); - background: var(--bg); - border: 1px solid var(--border); - border-radius: 5px; - box-shadow: none; - box-sizing: border-box; - width: 60%; - -moz-appearance: none; - -webkit-appearance: none; - appearance: none; -} - -/* Add arrow to */ -select { - background-image: linear-gradient(45deg, transparent 49%, var(--text) 51%), - linear-gradient(135deg, var(--text) 51%, transparent 49%); - background-position: calc(100% - 20px), calc(100% - 15px); - background-size: 5px 5px, 5px 5px; - background-repeat: no-repeat; -} - -select[multiple] { - background-image: none !important; -} - -/* checkbox and radio button style */ -input[type="checkbox"], -input[type="radio"] { - vertical-align: bottom; - position: relative; -} - -input[type="radio"] { - border-radius: 100%; -} - -input[type="checkbox"]:checked, -input[type="radio"]:checked { - background: var(--accent); -} - -input[type="checkbox"]:checked::after { - /* Creates a rectangle with colored right and bottom borders which is rotated to look like a check mark */ - content: " "; - width: 0.1em; - height: 0.25em; - border-radius: 0; - position: absolute; - top: 0.05em; - left: 0.18em; - background: transparent; - border-right: solid var(--bg) 0.08em; - border-bottom: solid var(--bg) 0.08em; - font-size: 1.8em; - transform: rotate(45deg); -} -input[type="radio"]:checked::after { - /* creates a colored circle for the checked radio button */ - content: " "; - width: 0.25em; - height: 0.25em; - border-radius: 100%; - position: absolute; - top: 0.125em; - background: var(--bg); - left: 0.125em; - font-size: 32px; -} - -/* Make the textarea wider than other inputs */ -textarea { - width: 80%; -} - -/* Makes input fields wider on smaller screens */ -@media only screen and (max-width: 720px) { - textarea, - select, - input { - width: 100%; - } -} - -/* Ensures the checkbox and radio inputs do not have a set width like other input fields */ -input[type="checkbox"], -input[type="radio"] { - width: auto; -} - -/* do not show border around file selector button */ -input[type="file"] { - border: 0; -} - -/* Without this any HTML using
shows ugly borders and has additional padding/margin. (Issue #3) */ -fieldset { - border: 0; - padding: 0; - margin: 0; -} - -/* Misc body elements */ - -hr { - color: var(--border); - border-top: 1px; - margin: 1rem auto; -} - -mark { - padding: 2px 5px; - border-radius: 4px; - background: var(--marked); -} - -main img, -main video { - max-width: 100%; - height: auto; - border-radius: 5px; -} - -figure { - margin: 0; -} - -figcaption { - font-size: 0.9rem; - color: var(--text-light); - text-align: center; - margin-bottom: 1rem; -} - -blockquote { - margin: 2rem 0 2rem 2rem; - padding: 0.4rem 0.8rem; - border-left: 0.35rem solid var(--accent); - opacity: 0.8; - font-style: italic; -} - -cite { - font-size: 0.9rem; - color: var(--text-light); - font-style: normal; -} - -/* Use mono font for code like elements */ -code, -pre, -pre span, -kbd, -samp { - font-size: 1.075rem; - font-family: var(--mono-font); - color: var(--code); -} - -kbd { - color: var(--preformatted); - border: 1px solid var(--preformatted); - border-bottom: 3px solid var(--preformatted); - border-radius: 5px; - padding: 0.1rem; -} - -pre { - padding: 1rem 1.4rem; - max-width: 100%; - overflow: auto; - overflow-x: auto; - color: var(--preformatted); - background: var(--accent-bg); - border: 1px solid var(--border); - border-radius: 5px; -} - -/* Fix embedded code within pre */ -pre code { - color: var(--preformatted); - background: none; - margin: 0; - padding: 0; +a { + color: blue; } diff --git a/ui/views/common.templ b/ui/views/common.templ new file mode 100644 index 0000000..94627fb --- /dev/null +++ b/ui/views/common.templ @@ -0,0 +1,81 @@ +package views + +import "git.32bit.cafe/32bitcafe/guestbook/internal/models" +import "strconv" + +type CommonData struct { + CurrentYear int + Flash string + IsAuthenticated bool + CSRFToken string + CurrentUser *models.User + IsHtmx bool +} + +func slugToShortId(slug string) uint64 { + id, _ := strconv.ParseUint(slug, 36, 64) + return id +} + +templ commonHeader() { +
+

webweav.ing

+
+} + +templ topNav(data CommonData) { + +} + + +templ commonFooter() { + +} + +templ base(title string, data CommonData) { + + + + { title } - webweav.ing + + + + + + + @commonHeader() + @topNav(data) +
+ if data.Flash != "" { +
{ data.Flash }
+ } + { children... } +
+ @commonFooter() + + +} + diff --git a/ui/views/common_templ.go b/ui/views/common_templ.go new file mode 100644 index 0000000..f1ab759 --- /dev/null +++ b/ui/views/common_templ.go @@ -0,0 +1,245 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package views + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "git.32bit.cafe/32bitcafe/guestbook/internal/models" +import "strconv" + +type CommonData struct { + CurrentYear int + Flash string + IsAuthenticated bool + CSRFToken string + CurrentUser *models.User + IsHtmx bool +} + +func slugToShortId(slug string) uint64 { + id, _ := strconv.ParseUint(slug, 36, 64) + return id +} + +func commonHeader() 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

webweav.ing

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func topNav(data CommonData) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func commonFooter() 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func base(title string, data CommonData) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 62, Col: 26} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " - webweav.ing") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = commonHeader().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = topNav(data).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if data.Flash != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(data.Flash) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 73, Col: 51} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ_7745c5c3_Var6.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = commonFooter().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/ui/views/common_templ.txt b/ui/views/common_templ.txt new file mode 100644 index 0000000..764fb67 --- /dev/null +++ b/ui/views/common_templ.txt @@ -0,0 +1,15 @@ +

webweav.ing

+ + + + - webweav.ing +
+
+
+
+ \ No newline at end of file diff --git a/ui/views/guestbooks.templ b/ui/views/guestbooks.templ new file mode 100644 index 0000000..4dfa950 --- /dev/null +++ b/ui/views/guestbooks.templ @@ -0,0 +1,116 @@ +package views + +import "fmt" +import "git.32bit.cafe/32bitcafe/guestbook/internal/models" + +templ gbCreateForm(csrf_token string) { + + + + +} + +templ gbList(guestbooks []models.Guestbook) { + if len(guestbooks) == 0 { +

No Guestbooks yet

+ } else { + + } +} + +templ GuestbookList(title string, data CommonData, guestbooks []models.Guestbook) { + if data.IsHtmx { + @gbList(guestbooks) + } else { + @base(title, data) { +

My Guestbooks

+
+ +
+ @gbList(guestbooks) + } + } +} + +templ GuestbookCreate(title string, data CommonData) { + if data.IsHtmx { +
+ @gbCreateForm(data.CSRFToken) +
+ } else { + @base(title, data) { +
+ @gbCreateForm(data.CSRFToken) +
+ } + } +} + +templ sidebar(guestbook models.Guestbook) { + {{ gbUrl := fmt.Sprintf("/guestbooks/%s", guestbook.Slug()) }} + +} + +templ GuestbookView(title string, data CommonData, guestbook models.Guestbook, comments []models.GuestbookComment) { + @base(title, data) { +
+ @sidebar(guestbook) +
+

Guestbook for { guestbook.SiteUrl }

+ {{ commentCreateUrl := fmt.Sprintf("/guestbooks/%s/comments/create", guestbook.Slug()) }} +

+ New Comment +

+ if len(comments) == 0 { +

No comments yet!

+ } + for _, c := range comments { +
+ { c.AuthorName } + { c.Created.Format("01-02-2006 03:04PM") } +

+ { c.CommentText } +

+
+ } +
+
+ } +} diff --git a/ui/views/guestbooks_templ.go b/ui/views/guestbooks_templ.go new file mode 100644 index 0000000..5150b61 --- /dev/null +++ b/ui/views/guestbooks_templ.go @@ -0,0 +1,481 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package views + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "fmt" +import "git.32bit.cafe/32bitcafe/guestbook/internal/models" + +func gbCreateForm(csrf_token string) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func gbList(guestbooks []models.Guestbook) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + if len(guestbooks) == 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

No Guestbooks yet

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) +} + +func GuestbookList(title string, data CommonData, guestbooks []models.Guestbook) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + if data.IsHtmx { + templ_7745c5c3_Err = gbList(guestbooks).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Var7 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

My Guestbooks

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = gbList(guestbooks).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var7), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) +} + +func GuestbookCreate(title string, data CommonData) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + if data.IsHtmx { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = gbCreateForm(data.CSRFToken).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Var9 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = gbCreateForm(data.CSRFToken).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) +} + +func sidebar(guestbook models.Guestbook) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + gbUrl := fmt.Sprintf("/guestbooks/%s", guestbook.Slug()) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func GuestbookView(title string, data CommonData, guestbook models.Guestbook, comments []models.GuestbookComment) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var17 := templ.GetChildren(ctx) + if templ_7745c5c3_Var17 == nil { + templ_7745c5c3_Var17 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var18 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = sidebar(guestbook).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "

Guestbook for ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var19 string + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(guestbook.SiteUrl) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 96, Col: 53} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + commentCreateUrl := fmt.Sprintf("/guestbooks/%s/comments/create", guestbook.Slug()) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "

New Comment

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if len(comments) == 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "

No comments yet!

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + for _, c := range comments { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var21 string + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(c.AuthorName) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 106, Col: 46} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var22 string + templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(c.Created.Format("01-02-2006 03:04PM")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 107, Col: 64} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var23 string + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(c.CommentText) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 109, Col: 43} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var18), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/ui/views/guestbooks_templ.txt b/ui/views/guestbooks_templ.txt new file mode 100644 index 0000000..b461ab8 --- /dev/null +++ b/ui/views/guestbooks_templ.txt @@ -0,0 +1,32 @@ + +

No Guestbooks yet

+ +

My Guestbooks

+
+
+
+
+ +
+

Guestbook for +

+

New Comment

+

No comments yet!

+
+ +

+

+
\ No newline at end of file diff --git a/ui/views/home.templ b/ui/views/home.templ new file mode 100644 index 0000000..ab1cd3f --- /dev/null +++ b/ui/views/home.templ @@ -0,0 +1,25 @@ +package views + +templ loggedInHome() { +

Tools

+

+ Guestbooks +

+} + +templ loggedOutHome() { +

Welcome

+

+ Welcome to webweav.ing, a collection of webmastery tools created by the 32-Bit Cafe. +

+} + +templ Home(title string, data CommonData) { + @base(title, data) { + if data.IsAuthenticated { + @loggedInHome() + } else { + @loggedOutHome() + } + } +} diff --git a/ui/views/home_templ.go b/ui/views/home_templ.go new file mode 100644 index 0000000..4448fbc --- /dev/null +++ b/ui/views/home_templ.go @@ -0,0 +1,123 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package views + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func loggedInHome() 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

Tools

Guestbooks

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func loggedOutHome() 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

Welcome

Welcome to webweav.ing, a collection of webmastery tools created by the 32-Bit Cafe.

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func Home(title string, data CommonData) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var4 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + if data.IsAuthenticated { + templ_7745c5c3_Err = loggedInHome().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = loggedOutHome().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) + templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var4), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/ui/views/home_templ.txt b/ui/views/home_templ.txt new file mode 100644 index 0000000..de7f60a --- /dev/null +++ b/ui/views/home_templ.txt @@ -0,0 +1,2 @@ +

Tools

Guestbooks

+

Welcome

Welcome to webweav.ing, a collection of webmastery tools created by the 32-Bit Cafe.

\ No newline at end of file diff --git a/ui/views/users.templ b/ui/views/users.templ new file mode 100644 index 0000000..46467c8 --- /dev/null +++ b/ui/views/users.templ @@ -0,0 +1,83 @@ +package views + +import ( + "git.32bit.cafe/32bitcafe/guestbook/internal/forms" + "git.32bit.cafe/32bitcafe/guestbook/internal/models" +) + +templ UserLogin (title string, data CommonData, form forms.UserLoginForm) { + @base(title, data) { +

Login

+
+ + for _, error := range form.NonFieldErrors { +
{ error }
+ } +
+ + {{ error, exists := form.FieldErrors["email"] }} + if exists { + + } + +
+
+ + {{ error, exists = form.FieldErrors["password"] }} + if exists { + + } + +
+
+ +
+
+ } +} + +templ UserRegistration (title string, data CommonData, form forms.UserRegistrationForm) { + @base(title, data) { +

User Registration

+
+ +
+ {{ error, exists := form.FieldErrors["name"] }} + + if exists { + + } + +
+
+ {{ error, exists = form.FieldErrors["email"] }} + + if exists { + + } + +
+
+ {{ error, exists = form.FieldErrors["password"] }} + + if exists { + + } + +
+
+ +
+
+ } +} + +templ UserProfile (title string, data CommonData, user models.User) { + @base(title, data) { +

{ user.Username }

+

{ user.Email }

+ } +} + +templ UserSettings () { +} diff --git a/ui/views/users_templ.go b/ui/views/users_templ.go new file mode 100644 index 0000000..661a6f5 --- /dev/null +++ b/ui/views/users_templ.go @@ -0,0 +1,428 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package views + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "git.32bit.cafe/32bitcafe/guestbook/internal/forms" + "git.32bit.cafe/32bitcafe/guestbook/internal/models" +) + +func UserLogin(title string, data CommonData, form forms.UserLoginForm) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

Login

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, error := range form.NonFieldErrors { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(error) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 14, Col: 42} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + 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 = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + error, exists := form.FieldErrors["email"] + if exists { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " ") + 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 + } + error, exists = form.FieldErrors["password"] + if exists { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func UserRegistration(title string, data CommonData, form forms.UserRegistrationForm) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var9 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "

User Registration

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + error, exists := form.FieldErrors["name"] + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if exists { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + error, exists = form.FieldErrors["email"] + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if exists { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + error, exists = form.FieldErrors["password"] + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if exists { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func UserProfile(title string, data CommonData, user models.User) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var16 := templ.GetChildren(ctx) + if templ_7745c5c3_Var16 == nil { + templ_7745c5c3_Var16 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var17 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var18 string + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(user.Username) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 77, Col: 27} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var19 string + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(user.Email) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 78, Col: 23} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var17), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func UserSettings() 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var20 := templ.GetChildren(ctx) + if templ_7745c5c3_Var20 == nil { + templ_7745c5c3_Var20 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/ui/views/users_templ.txt b/ui/views/users_templ.txt new file mode 100644 index 0000000..963bde9 --- /dev/null +++ b/ui/views/users_templ.txt @@ -0,0 +1,31 @@ +

Login

+
+
+
+ +
+ +
+

User Registration

+ + +
+ + +
+ + +
+

+

+

\ No newline at end of file