Implement remote embedding of guestbooks #25
| @ -1,6 +1,7 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"encoding/json" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| @ -136,6 +137,30 @@ func (app *application) getGuestbookComments(w http.ResponseWriter, r *http.Requ | |||||||
| 	views.GuestbookDashboardCommentsView("Comments", data, website, website.Guestbook, comments).Render(r.Context(), w) | 	views.GuestbookDashboardCommentsView("Comments", data, website, website.Guestbook, comments).Render(r.Context(), w) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (app *application) getGuestbookCommentsSerialized(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 	slug := r.PathValue("id") | ||||||
|  | 	website, err := app.websites.Get(slugToShortId(slug)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if errors.Is(err, models.ErrNoRecord) { | ||||||
|  | 			http.NotFound(w, r) | ||||||
|  | 		} else { | ||||||
|  | 			app.serverError(w, r, err) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if !website.Guestbook.Settings.IsVisible || !website.Guestbook.Settings.AllowRemoteHostAccess { | ||||||
|  | 		app.clientError(w, http.StatusForbidden) | ||||||
|  | 	} | ||||||
|  | 	comments, err := app.guestbookComments.GetAllSerialized(website.Guestbook.ID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		app.serverError(w, r, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	b, err := json.Marshal(comments) | ||||||
|  | 	w.Write(b) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (app *application) getGuestbookCommentCreate(w http.ResponseWriter, r *http.Request) { | func (app *application) getGuestbookCommentCreate(w http.ResponseWriter, r *http.Request) { | ||||||
| 	// TODO: This will be the embeddable form | 	// TODO: This will be the embeddable form | ||||||
| 	slug := r.PathValue("id") | 	slug := r.PathValue("id") | ||||||
| @ -148,13 +173,21 @@ func (app *application) getGuestbookCommentCreate(w http.ResponseWriter, r *http | |||||||
| 		} | 		} | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	s := website.Guestbook.Settings | ||||||
|  | 	if !s.IsVisible || !s.AllowRemoteHostAccess || !website.Guestbook.CanComment() { | ||||||
|  | 		app.clientError(w, http.StatusForbidden) | ||||||
|  | 	} | ||||||
| 	data := app.newCommonData(r) | 	data := app.newCommonData(r) | ||||||
| 	form := forms.CommentCreateForm{} | 	form := forms.CommentCreateForm{} | ||||||
| 	views.CreateGuestbookComment("New Comment", data, website, website.Guestbook, form).Render(r.Context(), w) | 	views.EmbeddableGuestbookCommentForm(data, website, form).Render(r.Context(), w) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *http.Request) { | func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *http.Request) { | ||||||
| 	slug := r.PathValue("id") | 	slug := r.PathValue("id") | ||||||
|  | 	headless, err := strconv.ParseBool(r.URL.Query().Get("headless")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		headless = false | ||||||
|  | 	} | ||||||
| 	website, err := app.websites.Get(slugToShortId(slug)) | 	website, err := app.websites.Get(slugToShortId(slug)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		if errors.Is(err, models.ErrNoRecord) { | 		if errors.Is(err, models.ErrNoRecord) { | ||||||
| @ -184,14 +217,17 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt | |||||||
| 	form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank") | 	form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank") | ||||||
| 
 | 
 | ||||||
| 	if !form.Valid() { | 	if !form.Valid() { | ||||||
|  | 		data := app.newCommonData(r) | ||||||
|  | 		w.WriteHeader(http.StatusUnprocessableEntity) | ||||||
|  | 		if headless { | ||||||
|  | 			views.EmbeddableGuestbookCommentForm(data, website, form).Render(r.Context(), w) | ||||||
|  | 		} | ||||||
| 		// TODO: use htmx to avoid getting comments again | 		// TODO: use htmx to avoid getting comments again | ||||||
| 		comments, err := app.guestbookComments.GetAll(website.Guestbook.ID) | 		comments, err := app.guestbookComments.GetAll(website.Guestbook.ID) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			app.serverError(w, r, err) | 			app.serverError(w, r, err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		data := app.newCommonData(r) |  | ||||||
| 		w.WriteHeader(http.StatusUnprocessableEntity) |  | ||||||
| 		views.GuestbookView("Guestbook", data, website, website.Guestbook, comments, form).Render(r.Context(), w) | 		views.GuestbookView("Guestbook", data, website, website.Guestbook, comments, form).Render(r.Context(), w) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @ -203,9 +239,70 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	app.sessionManager.Put(r.Context(), "flash", "Comment successfully posted!") | 	app.sessionManager.Put(r.Context(), "flash", "Comment successfully posted!") | ||||||
|  | 	if headless { | ||||||
|  | 		http.Redirect(w, r, fmt.Sprintf("/websites/%s/guestbook/comments/create", slug), http.StatusSeeOther) | ||||||
|  | 	} | ||||||
| 	http.Redirect(w, r, fmt.Sprintf("/websites/%s/guestbook", slug), http.StatusSeeOther) | 	http.Redirect(w, r, fmt.Sprintf("/websites/%s/guestbook", slug), http.StatusSeeOther) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (app *application) postGuestbookCommentCreateRemote(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 	slug := r.PathValue("id") | ||||||
|  | 	website, err := app.websites.Get(slugToShortId(slug)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if errors.Is(err, models.ErrNoRecord) { | ||||||
|  | 			http.NotFound(w, r) | ||||||
|  | 		} else { | ||||||
|  | 			app.serverError(w, r, err) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !matchOrigin(r.Header.Get("Origin"), website.Url) { | ||||||
|  | 		app.clientError(w, http.StatusForbidden) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if !website.Guestbook.CanComment() { | ||||||
|  | 		app.clientError(w, http.StatusForbidden) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var form forms.CommentCreateForm | ||||||
|  | 	err = app.decodePostForm(r, &form) | ||||||
|  | 	if err != nil { | ||||||
|  | 		app.clientError(w, http.StatusBadRequest) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	form.CheckField(validator.NotBlank(form.AuthorName), "authorName", "This field cannot be blank") | ||||||
|  | 	form.CheckField(validator.MaxChars(form.AuthorName, 256), "authorName", "This field cannot be more than 256 characters long") | ||||||
|  | 	form.CheckField(validator.MaxChars(form.AuthorEmail, 256), "authorEmail", "This field cannot be more than 256 characters long") | ||||||
|  | 	form.CheckField(validator.MaxChars(form.AuthorSite, 256), "authorSite", "This field cannot be more than 256 characters long") | ||||||
|  | 	form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank") | ||||||
|  | 
 | ||||||
|  | 	// if redirect path is filled out, redirect to that path on the website host | ||||||
|  | 	// otherwise redirect to the guestbook by default | ||||||
|  | 	redirectUrl := fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(website.ShortId)) | ||||||
|  | 	if form.Redirect != "" { | ||||||
|  | 		u, err := website.Url.Parse(form.Redirect) | ||||||
|  | 		if err == nil { | ||||||
|  | 			redirectUrl = u.String() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !form.Valid() { | ||||||
|  | 		views.GuestbookCommentCreateRemoteErrorView(redirectUrl, "Invalid Input").Render(r.Context(), w) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	shortId := app.createShortId() | ||||||
|  | 	_, err = app.guestbookComments.Insert(shortId, website.Guestbook.ID, 0, form.AuthorName, form.AuthorEmail, form.AuthorSite, form.Content, "", true) | ||||||
|  | 	if err != nil { | ||||||
|  | 		app.serverError(w, r, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	views.GuestbookCommentCreateRemoteSuccessView(redirectUrl).Render(r.Context(), w) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (app *application) getCommentQueue(w http.ResponseWriter, r *http.Request) { | func (app *application) getCommentQueue(w http.ResponseWriter, r *http.Request) { | ||||||
| 	slug := r.PathValue("id") | 	slug := r.PathValue("id") | ||||||
| 	website, err := app.websites.Get(slugToShortId(slug)) | 	website, err := app.websites.Get(slugToShortId(slug)) | ||||||
|  | |||||||
| @ -144,3 +144,88 @@ func TestPostGuestbookCommentCreate(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestPostGuestbookCommentCreateRemote(t *testing.T) { | ||||||
|  | 	app := newTestApplication(t) | ||||||
|  | 	ts := newTestServer(t, app.routes()) | ||||||
|  | 	defer ts.Close() | ||||||
|  | 
 | ||||||
|  | 	_, _, body := ts.get(t, fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(1))) | ||||||
|  | 	validCSRFToken := extractCSRFToken(t, body) | ||||||
|  | 
 | ||||||
|  | 	const ( | ||||||
|  | 		validAuthorName  = "John Test" | ||||||
|  | 		validAuthorEmail = "test@example.com" | ||||||
|  | 		validAuthorSite  = "example.com" | ||||||
|  | 		validContent     = "This is a comment" | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	tests := []struct { | ||||||
|  | 		name        string | ||||||
|  | 		authorName  string | ||||||
|  | 		authorEmail string | ||||||
|  | 		authorSite  string | ||||||
|  | 		content     string | ||||||
|  | 		csrfToken   string | ||||||
|  | 		wantCode    int | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			name:        "Valid input", | ||||||
|  | 			authorName:  validAuthorName, | ||||||
|  | 			authorEmail: validAuthorEmail, | ||||||
|  | 			authorSite:  validAuthorSite, | ||||||
|  | 			content:     validContent, | ||||||
|  | 			csrfToken:   validCSRFToken, | ||||||
|  | 			wantCode:    http.StatusSeeOther, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Blank name", | ||||||
|  | 			authorName:  "", | ||||||
|  | 			authorEmail: validAuthorEmail, | ||||||
|  | 			authorSite:  validAuthorSite, | ||||||
|  | 			content:     validContent, | ||||||
|  | 			csrfToken:   validCSRFToken, | ||||||
|  | 			wantCode:    http.StatusUnprocessableEntity, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Blank email", | ||||||
|  | 			authorName:  validAuthorName, | ||||||
|  | 			authorEmail: "", | ||||||
|  | 			authorSite:  validAuthorSite, | ||||||
|  | 			content:     validContent, | ||||||
|  | 			csrfToken:   validCSRFToken, | ||||||
|  | 			wantCode:    http.StatusSeeOther, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Blank site", | ||||||
|  | 			authorName:  validAuthorName, | ||||||
|  | 			authorEmail: validAuthorEmail, | ||||||
|  | 			authorSite:  "", | ||||||
|  | 			content:     validContent, | ||||||
|  | 			csrfToken:   validCSRFToken, | ||||||
|  | 			wantCode:    http.StatusSeeOther, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Blank content", | ||||||
|  | 			authorName:  validAuthorName, | ||||||
|  | 			authorEmail: validAuthorEmail, | ||||||
|  | 			authorSite:  validAuthorSite, | ||||||
|  | 			content:     "", | ||||||
|  | 			csrfToken:   validCSRFToken, | ||||||
|  | 			wantCode:    http.StatusUnprocessableEntity, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	for _, tt := range tests { | ||||||
|  | 		t.Run(tt.name, func(t *testing.T) { | ||||||
|  | 			form := url.Values{} | ||||||
|  | 			form.Add("authorname", tt.authorName) | ||||||
|  | 			form.Add("authoremail", tt.authorEmail) | ||||||
|  | 			form.Add("authorsite", tt.authorSite) | ||||||
|  | 			form.Add("content", tt.content) | ||||||
|  | 			form.Add("csrf_token", tt.csrfToken) | ||||||
|  | 			code, _, body := ts.postForm(t, fmt.Sprintf("/websites/%s/guestbook/comments/create/remote", shortIdToSlug(1)), form) | ||||||
|  | 			assert.Equal(t, code, tt.wantCode) | ||||||
|  | 			assert.Equal(t, body, body) | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ import ( | |||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"net/url" | ||||||
| 
 | 
 | ||||||
| 	"git.32bit.cafe/32bitcafe/guestbook/internal/forms" | 	"git.32bit.cafe/32bitcafe/guestbook/internal/forms" | ||||||
| 	"git.32bit.cafe/32bitcafe/guestbook/internal/models" | 	"git.32bit.cafe/32bitcafe/guestbook/internal/models" | ||||||
| @ -32,14 +33,20 @@ func (app *application) postWebsiteCreate(w http.ResponseWriter, r *http.Request | |||||||
| 	form.CheckField(validator.MaxChars(form.Name, 256), "sitename", "This field cannot exceed 256 characters") | 	form.CheckField(validator.MaxChars(form.Name, 256), "sitename", "This field cannot exceed 256 characters") | ||||||
| 	form.CheckField(validator.NotBlank(form.SiteUrl), "siteurl", "This field cannot be blank") | 	form.CheckField(validator.NotBlank(form.SiteUrl), "siteurl", "This field cannot be blank") | ||||||
| 	form.CheckField(validator.MaxChars(form.SiteUrl, 512), "siteurl", "This field cannot exceed 512 characters") | 	form.CheckField(validator.MaxChars(form.SiteUrl, 512), "siteurl", "This field cannot exceed 512 characters") | ||||||
|  | 	form.CheckField(validator.Matches(form.SiteUrl, validator.WebRX), "siteurl", "This field must be a valid URL (including http:// or https://)") | ||||||
| 
 | 
 | ||||||
|  | 	u, err := url.Parse(form.SiteUrl) | ||||||
|  | 	if err != nil { | ||||||
|  | 		form.CheckField(false, "siteurl", "This field must be a valid URL") | ||||||
|  | 	} | ||||||
| 	if !form.Valid() { | 	if !form.Valid() { | ||||||
| 		data := app.newCommonData(r) | 		data := app.newCommonData(r) | ||||||
| 		w.WriteHeader(http.StatusUnprocessableEntity) | 		w.WriteHeader(http.StatusUnprocessableEntity) | ||||||
| 		views.WebsiteCreate("Add a Website", data, form).Render(r.Context(), w) | 		views.WebsiteCreate("Add a Website", data, form).Render(r.Context(), w) | ||||||
|  | 		return | ||||||
| 	} | 	} | ||||||
| 	websiteShortID := app.createShortId() | 	websiteShortID := app.createShortId() | ||||||
| 	_, err = app.websites.Insert(websiteShortID, userId, form.Name, form.SiteUrl, form.AuthorName) | 	_, err = app.websites.Insert(websiteShortID, userId, form.Name, u.String(), form.AuthorName) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		app.serverError(w, r, err) | 		app.serverError(w, r, err) | ||||||
| 		return | 		return | ||||||
| @ -75,10 +82,6 @@ func (app *application) getWebsiteList(w http.ResponseWriter, r *http.Request) { | |||||||
| 		app.serverError(w, r, err) | 		app.serverError(w, r, err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if r.Header.Get("HX-Request") == "true" { |  | ||||||
| 		views.HxWebsiteList(websites) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	data := app.newCommonData(r) | 	data := app.newCommonData(r) | ||||||
| 	views.WebsiteList("My Websites", data, websites).Render(r.Context(), w) | 	views.WebsiteList("My Websites", data, websites).Render(r.Context(), w) | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"math" | 	"math" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"net/url" | ||||||
| 	"runtime/debug" | 	"runtime/debug" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"time" | 	"time" | ||||||
| @ -109,6 +110,7 @@ func (app *application) newCommonData(r *http.Request) views.CommonData { | |||||||
| 		CSRFToken:       nosurf.Token(r), | 		CSRFToken:       nosurf.Token(r), | ||||||
| 		CurrentUser:     app.getCurrentUser(r), | 		CurrentUser:     app.getCurrentUser(r), | ||||||
| 		IsHtmx:          r.Header.Get("Hx-Request") == "true", | 		IsHtmx:          r.Header.Get("Hx-Request") == "true", | ||||||
|  | 		RootUrl:         app.rootUrl, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -127,3 +129,14 @@ func (app *application) durationToTime(duration string) (time.Time, error) { | |||||||
| 	result = time.Now().UTC().Add(offset) | 	result = time.Now().UTC().Add(offset) | ||||||
| 	return result, nil | 	return result, nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func matchOrigin(origin string, u *url.URL) bool { | ||||||
|  | 	o, err := url.Parse(origin) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	if o.Host != u.Host { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | |||||||
| @ -28,12 +28,14 @@ type application struct { | |||||||
| 	formDecoder       *schema.Decoder | 	formDecoder       *schema.Decoder | ||||||
| 	debug             bool | 	debug             bool | ||||||
| 	timezones         []string | 	timezones         []string | ||||||
|  | 	rootUrl           string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
| 	addr := flag.String("addr", ":3000", "HTTP network address") | 	addr := flag.String("addr", ":3000", "HTTP network address") | ||||||
| 	dsn := flag.String("dsn", "guestbook.db", "data source name") | 	dsn := flag.String("dsn", "guestbook.db", "data source name") | ||||||
| 	debug := flag.Bool("debug", false, "enable debug mode") | 	debug := flag.Bool("debug", false, "enable debug mode") | ||||||
|  | 	root := flag.String("root", "localhost:3000", "root URL of application") | ||||||
| 	flag.Parse() | 	flag.Parse() | ||||||
| 
 | 
 | ||||||
| 	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) | 	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) | ||||||
| @ -62,6 +64,7 @@ func main() { | |||||||
| 		formDecoder:       formDecoder, | 		formDecoder:       formDecoder, | ||||||
| 		debug:             *debug, | 		debug:             *debug, | ||||||
| 		timezones:         getAvailableTimezones(), | 		timezones:         getAvailableTimezones(), | ||||||
|  | 		rootUrl:           *root, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = app.users.InitializeSettingsMap() | 	err = app.users.InitializeSettingsMap() | ||||||
|  | |||||||
| @ -8,87 +8,94 @@ import ( | |||||||
| 	"github.com/justinas/nosurf" | 	"github.com/justinas/nosurf" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func (app *application) logRequest (next http.Handler) http.Handler { | func (app *application) logRequest(next http.Handler) http.Handler { | ||||||
|     return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
|         var ( | 		var ( | ||||||
|             ip = r.RemoteAddr | 			ip     = r.RemoteAddr | ||||||
|             proto = r.Proto | 			proto  = r.Proto | ||||||
|             method = r.Method | 			method = r.Method | ||||||
|             uri = r.URL.RequestURI() | 			uri    = r.URL.RequestURI() | ||||||
|         ) | 		) | ||||||
|         app.logger.Info("received request", "ip", ip, "proto", proto, "method", method, "uri", uri) | 		app.logger.Info("received request", "ip", ip, "proto", proto, "method", method, "uri", uri) | ||||||
|         next.ServeHTTP(w, r) | 		next.ServeHTTP(w, r) | ||||||
|     }) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func commonHeaders (next http.Handler) http.Handler { | func commonHeaders(next http.Handler) http.Handler { | ||||||
|     return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
|         w.Header().Set("Content-Security-Policy", "default-src 'self'; style-src 'self' fonts.googleapis.com; font-src fonts.gstatic.com") | 		w.Header().Set("Content-Security-Policy", "default-src 'self'; style-src 'self' fonts.googleapis.com; font-src fonts.gstatic.com") | ||||||
|         w.Header().Set("Referrer-Policy", "origin-when-cross-origin") | 		w.Header().Set("Referrer-Policy", "origin-when-cross-origin") | ||||||
|         w.Header().Set("X-Content-Type-Options", "nosniff") | 		w.Header().Set("X-Content-Type-Options", "nosniff") | ||||||
|         // w.Header().Set("X-Frame-Options", "deny") | 		// w.Header().Set("X-Frame-Options", "deny") | ||||||
|         w.Header().Set("X-XSS-Protection", "0") | 		w.Header().Set("X-XSS-Protection", "0") | ||||||
|         next.ServeHTTP(w, r) | 		next.ServeHTTP(w, r) | ||||||
|     }) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (app *application) recoverPanic(next http.Handler) http.Handler { | func (app *application) recoverPanic(next http.Handler) http.Handler { | ||||||
|     return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
|         defer func() { | 		defer func() { | ||||||
|             if err := recover(); err != nil { | 			if err := recover(); err != nil { | ||||||
|                 w.Header().Set("Connection", "close") | 				w.Header().Set("Connection", "close") | ||||||
|                 app.serverError(w, r, fmt.Errorf("%s", err)) | 				app.serverError(w, r, fmt.Errorf("%s", err)) | ||||||
|             } | 			} | ||||||
|         }() | 		}() | ||||||
| 
 | 
 | ||||||
|         next.ServeHTTP(w, r) | 		next.ServeHTTP(w, r) | ||||||
|     }) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (app *application) requireAuthentication(next http.Handler) http.Handler { | func (app *application) requireAuthentication(next http.Handler) http.Handler { | ||||||
|     return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
|         if !app.isAuthenticated(r) { | 		if !app.isAuthenticated(r) { | ||||||
|             http.Redirect(w, r, "/users/login", http.StatusSeeOther) | 			http.Redirect(w, r, "/users/login", http.StatusSeeOther) | ||||||
|             return | 			return | ||||||
|         } | 		} | ||||||
|         w.Header().Add("Cache-Control", "no-store") | 		w.Header().Add("Cache-Control", "no-store") | ||||||
|         next.ServeHTTP(w, r) | 		next.ServeHTTP(w, r) | ||||||
|     }) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func noSurf(next http.Handler) http.Handler { | func noSurf(next http.Handler) http.Handler { | ||||||
|     csrfHandler := nosurf.New(next) | 	csrfHandler := nosurf.New(next) | ||||||
|     csrfHandler.SetBaseCookie(http.Cookie{ | 	csrfHandler.SetBaseCookie(http.Cookie{ | ||||||
|         HttpOnly: true, | 		HttpOnly: true, | ||||||
|         Path: "/", | 		Path:     "/", | ||||||
|         Secure: true, | 		Secure:   true, | ||||||
|     }) | 	}) | ||||||
| 
 | 
 | ||||||
|     return csrfHandler | 	return csrfHandler | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (app *application) authenticate(next http.Handler) http.Handler { | func (app *application) authenticate(next http.Handler) http.Handler { | ||||||
|     return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
|         id := app.sessionManager.GetInt64(r.Context(), "authenticatedUserId") | 		id := app.sessionManager.GetInt64(r.Context(), "authenticatedUserId") | ||||||
|         if id == 0 { | 		if id == 0 { | ||||||
|             next.ServeHTTP(w, r) | 			next.ServeHTTP(w, r) | ||||||
|             return | 			return | ||||||
|         } | 		} | ||||||
|         exists, err := app.users.Exists(id) | 		exists, err := app.users.Exists(id) | ||||||
|         if err != nil { | 		if err != nil { | ||||||
|             app.serverError(w, r, err) | 			app.serverError(w, r, err) | ||||||
|             return | 			return | ||||||
|         } | 		} | ||||||
|         user, err := app.users.GetById(id) | 		user, err := app.users.GetById(id) | ||||||
|         if err != nil { | 		if err != nil { | ||||||
|             app.serverError(w, r, err) | 			app.serverError(w, r, err) | ||||||
|             return | 			return | ||||||
|         } | 		} | ||||||
|         if exists { | 		if exists { | ||||||
|             ctx := context.WithValue(r.Context(), isAuthenticatedContextKey, true) | 			ctx := context.WithValue(r.Context(), isAuthenticatedContextKey, true) | ||||||
|             ctx = context.WithValue(ctx, userNameContextKey, user) | 			ctx = context.WithValue(ctx, userNameContextKey, user) | ||||||
|             r = r.WithContext(ctx) | 			r = r.WithContext(ctx) | ||||||
|         } | 		} | ||||||
|         next.ServeHTTP(w, r) | 		next.ServeHTTP(w, r) | ||||||
|     }) | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (app *application) enableCors(next http.Handler) http.Handler { | ||||||
|  | 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 		w.Header().Set("Access-Control-Allow-Origin", "*") | ||||||
|  | 		next.ServeHTTP(w, r) | ||||||
|  | 	}) | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,10 +15,14 @@ func (app *application) routes() http.Handler { | |||||||
| 
 | 
 | ||||||
| 	dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf, app.authenticate) | 	dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf, app.authenticate) | ||||||
| 	standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders) | 	standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders) | ||||||
|  | 	withCors := standard.Append(app.enableCors) | ||||||
| 
 | 
 | ||||||
| 	mux.Handle("/{$}", dynamic.ThenFunc(app.home)) | 	mux.Handle("/{$}", dynamic.ThenFunc(app.home)) | ||||||
| 	mux.Handle("POST /websites/{id}/guestbook/comments/create", dynamic.ThenFunc(app.postGuestbookCommentCreate)) |  | ||||||
| 	mux.Handle("GET /websites/{id}/guestbook", dynamic.ThenFunc(app.getGuestbook)) | 	mux.Handle("GET /websites/{id}/guestbook", dynamic.ThenFunc(app.getGuestbook)) | ||||||
|  | 	mux.Handle("GET /websites/{id}/guestbook/comments", withCors.ThenFunc(app.getGuestbookCommentsSerialized)) | ||||||
|  | 	mux.Handle("POST /websites/{id}/guestbook/comments/create/remote", standard.ThenFunc(app.postGuestbookCommentCreateRemote)) | ||||||
|  | 	mux.Handle("GET /websites/{id}/guestbook/comments/create", dynamic.ThenFunc(app.getGuestbookCommentCreate)) | ||||||
|  | 	mux.Handle("POST /websites/{id}/guestbook/comments/create", dynamic.ThenFunc(app.postGuestbookCommentCreate)) | ||||||
| 	mux.Handle("GET /users/register", dynamic.ThenFunc(app.getUserRegister)) | 	mux.Handle("GET /users/register", dynamic.ThenFunc(app.getUserRegister)) | ||||||
| 	mux.Handle("POST /users/register", dynamic.ThenFunc(app.postUserRegister)) | 	mux.Handle("POST /users/register", dynamic.ThenFunc(app.postUserRegister)) | ||||||
| 	mux.Handle("GET /users/login", dynamic.ThenFunc(app.getUserLogin)) | 	mux.Handle("GET /users/login", dynamic.ThenFunc(app.getUserLogin)) | ||||||
| @ -48,7 +52,6 @@ func (app *application) routes() http.Handler { | |||||||
| 	mux.Handle("GET /websites/{id}/dashboard/guestbook/comments/trash", protected.ThenFunc(app.getCommentTrash)) | 	mux.Handle("GET /websites/{id}/dashboard/guestbook/comments/trash", protected.ThenFunc(app.getCommentTrash)) | ||||||
| 	mux.Handle("GET /websites/{id}/dashboard/guestbook/themes", protected.ThenFunc(app.getComingSoon)) | 	mux.Handle("GET /websites/{id}/dashboard/guestbook/themes", protected.ThenFunc(app.getComingSoon)) | ||||||
| 	mux.Handle("GET /websites/{id}/dashboard/guestbook/customize", protected.ThenFunc(app.getComingSoon)) | 	mux.Handle("GET /websites/{id}/dashboard/guestbook/customize", protected.ThenFunc(app.getComingSoon)) | ||||||
| 	mux.Handle("GET /websites/{id}/guestbook/comments/create", protected.ThenFunc(app.getGuestbookCommentCreate)) |  | ||||||
| 
 | 
 | ||||||
| 	return standard.Then(mux) | 	return standard.Then(mux) | ||||||
| } | } | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ type CommentCreateForm struct { | |||||||
| 	AuthorEmail         string `schema:"authoremail"` | 	AuthorEmail         string `schema:"authoremail"` | ||||||
| 	AuthorSite          string `schema:"authorsite"` | 	AuthorSite          string `schema:"authorsite"` | ||||||
| 	Content             string `schema:"content"` | 	Content             string `schema:"content"` | ||||||
|  | 	Redirect            string `schema:"redirect"` | ||||||
| 	validator.Validator `schema:"-"` | 	validator.Validator `schema:"-"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -20,6 +20,12 @@ type GuestbookComment struct { | |||||||
| 	IsPublished bool | 	IsPublished bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type GuestbookCommentSerialized struct { | ||||||
|  | 	AuthorName  string | ||||||
|  | 	CommentText string | ||||||
|  | 	Created     string | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type GuestbookCommentModel struct { | type GuestbookCommentModel struct { | ||||||
| 	DB *sql.DB | 	DB *sql.DB | ||||||
| } | } | ||||||
| @ -28,6 +34,7 @@ type GuestbookCommentModelInterface interface { | |||||||
| 	Insert(shortId uint64, guestbookId, parentId int64, authorName, authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) | 	Insert(shortId uint64, guestbookId, parentId int64, authorName, authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) | ||||||
| 	Get(shortId uint64) (GuestbookComment, error) | 	Get(shortId uint64) (GuestbookComment, error) | ||||||
| 	GetAll(guestbookId int64) ([]GuestbookComment, error) | 	GetAll(guestbookId int64) ([]GuestbookComment, error) | ||||||
|  | 	GetAllSerialized(guestbookId int64) ([]GuestbookCommentSerialized, error) | ||||||
| 	GetDeleted(guestbookId int64) ([]GuestbookComment, error) | 	GetDeleted(guestbookId int64) ([]GuestbookComment, error) | ||||||
| 	GetUnpublished(guestbookId int64) ([]GuestbookComment, error) | 	GetUnpublished(guestbookId int64) ([]GuestbookComment, error) | ||||||
| 	UpdateComment(comment *GuestbookComment) error | 	UpdateComment(comment *GuestbookComment) error | ||||||
| @ -93,6 +100,30 @@ func (m *GuestbookCommentModel) GetAll(guestbookId int64) ([]GuestbookComment, e | |||||||
| 	return comments, nil | 	return comments, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (m *GuestbookCommentModel) GetAllSerialized(guestbookId int64) ([]GuestbookCommentSerialized, error) { | ||||||
|  | 	stmt := `SELECT AuthorName, CommentText, Created | ||||||
|  | 	    FROM guestbook_comments  | ||||||
|  | 	    WHERE GuestbookId = ? AND IsPublished = TRUE AND DELETED IS NULL | ||||||
|  | 	    ORDER BY Created DESC` | ||||||
|  | 	rows, err := m.DB.Query(stmt, guestbookId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	var comments []GuestbookCommentSerialized | ||||||
|  | 	for rows.Next() { | ||||||
|  | 		var c GuestbookCommentSerialized | ||||||
|  | 		err = rows.Scan(&c.AuthorName, &c.CommentText, &c.Created) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		comments = append(comments, c) | ||||||
|  | 	} | ||||||
|  | 	if err = rows.Err(); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return comments, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (m *GuestbookCommentModel) GetDeleted(guestbookId int64) ([]GuestbookComment, error) { | func (m *GuestbookCommentModel) GetDeleted(guestbookId int64) ([]GuestbookComment, error) { | ||||||
| 	stmt := `SELECT Id, ShortId, GuestbookId, ParentId, AuthorName, AuthorEmail, AuthorSite, | 	stmt := `SELECT Id, ShortId, GuestbookId, ParentId, AuthorName, AuthorEmail, AuthorSite, | ||||||
|     CommentText, PageUrl, Created, IsPublished, Deleted |     CommentText, PageUrl, Created, IsPublished, Deleted | ||||||
|  | |||||||
| @ -18,6 +18,12 @@ var mockGuestbookComment = models.GuestbookComment{ | |||||||
| 	IsPublished: true, | 	IsPublished: true, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | var mockSerializedGuestbookComment = models.GuestbookCommentSerialized{ | ||||||
|  | 	AuthorName:  "John Test", | ||||||
|  | 	CommentText: "Hello, world", | ||||||
|  | 	Created:     time.Now().Format(time.RFC3339), | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type GuestbookCommentModel struct{} | type GuestbookCommentModel struct{} | ||||||
| 
 | 
 | ||||||
| func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName, | func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName, | ||||||
| @ -45,6 +51,17 @@ func (m *GuestbookCommentModel) GetAll(guestbookId int64) ([]models.GuestbookCom | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (m *GuestbookCommentModel) GetAllSerialized(guestbookId int64) ([]models.GuestbookCommentSerialized, error) { | ||||||
|  | 	switch guestbookId { | ||||||
|  | 	case 1: | ||||||
|  | 		return []models.GuestbookCommentSerialized{mockSerializedGuestbookComment}, nil | ||||||
|  | 	case 2: | ||||||
|  | 		return []models.GuestbookCommentSerialized{}, nil | ||||||
|  | 	default: | ||||||
|  | 		return []models.GuestbookCommentSerialized{}, models.ErrNoRecord | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (m *GuestbookCommentModel) GetDeleted(guestbookId int64) ([]models.GuestbookComment, error) { | func (m *GuestbookCommentModel) GetDeleted(guestbookId int64) ([]models.GuestbookComment, error) { | ||||||
| 	switch guestbookId { | 	switch guestbookId { | ||||||
| 	default: | 	default: | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package mocks | package mocks | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"net/url" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"git.32bit.cafe/32bitcafe/guestbook/internal/models" | 	"git.32bit.cafe/32bitcafe/guestbook/internal/models" | ||||||
| @ -22,10 +23,14 @@ var mockGuestbook = models.Guestbook{ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var mockWebsite = models.Website{ | var mockWebsite = models.Website{ | ||||||
| 	ID:         1, | 	ID:      1, | ||||||
| 	ShortId:    1, | 	ShortId: 1, | ||||||
| 	Name:       "Example", | 	Name:    "Example", | ||||||
| 	SiteUrl:    "example.com", | 	// SiteUrl:    "example.com", | ||||||
|  | 	Url: &url.URL{ | ||||||
|  | 		Scheme: "http", | ||||||
|  | 		Host:   "example.com", | ||||||
|  | 	}, | ||||||
| 	AuthorName: "John Test", | 	AuthorName: "John Test", | ||||||
| 	UserId:     1, | 	UserId:     1, | ||||||
| 	Created:    time.Now(), | 	Created:    time.Now(), | ||||||
|  | |||||||
| @ -3,15 +3,17 @@ package models | |||||||
| import ( | import ( | ||||||
| 	"database/sql" | 	"database/sql" | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"net/url" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Website struct { | type Website struct { | ||||||
| 	ID         int64 | 	ID      int64 | ||||||
| 	ShortId    uint64 | 	ShortId uint64 | ||||||
| 	Name       string | 	Name    string | ||||||
| 	SiteUrl    string | 	// SiteUrl    string | ||||||
|  | 	Url        *url.URL | ||||||
| 	AuthorName string | 	AuthorName string | ||||||
| 	UserId     int64 | 	UserId     int64 | ||||||
| 	Created    time.Time | 	Created    time.Time | ||||||
| @ -179,7 +181,8 @@ func (m *WebsiteModel) Get(shortId uint64) (Website, error) { | |||||||
| 	} | 	} | ||||||
| 	row := tx.QueryRow(stmt, shortId) | 	row := tx.QueryRow(stmt, shortId) | ||||||
| 	var w Website | 	var w Website | ||||||
| 	err = row.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created) | 	var u string | ||||||
|  | 	err = row.Scan(&w.ID, &w.ShortId, &w.Name, &u, &w.AuthorName, &w.UserId, &w.Created) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		if errors.Is(err, sql.ErrNoRows) { | 		if errors.Is(err, sql.ErrNoRows) { | ||||||
| 			err = ErrNoRecord | 			err = ErrNoRecord | ||||||
| @ -189,6 +192,10 @@ func (m *WebsiteModel) Get(shortId uint64) (Website, error) { | |||||||
| 		} | 		} | ||||||
| 		return Website{}, err | 		return Website{}, err | ||||||
| 	} | 	} | ||||||
|  | 	w.Url, err = url.Parse(u) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return Website{}, err | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	stmt = `SELECT Id, ShortId, UserId, WebsiteId, Created, IsActive FROM guestbooks | 	stmt = `SELECT Id, ShortId, UserId, WebsiteId, Created, IsActive FROM guestbooks | ||||||
|     WHERE WebsiteId = ? AND Deleted IS NULL` |     WHERE WebsiteId = ? AND Deleted IS NULL` | ||||||
| @ -244,11 +251,16 @@ func (m *WebsiteModel) GetAllUser(userId int64) ([]Website, error) { | |||||||
| 	var websites []Website | 	var websites []Website | ||||||
| 	for rows.Next() { | 	for rows.Next() { | ||||||
| 		var w Website | 		var w Website | ||||||
| 		err := rows.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created, | 		var u string | ||||||
|  | 		err := rows.Scan(&w.ID, &w.ShortId, &w.Name, &u, &w.AuthorName, &w.UserId, &w.Created, | ||||||
| 			&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive) | 			&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
|  | 		w.Url, err = url.Parse(u) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
| 		websites = append(websites, w) | 		websites = append(websites, w) | ||||||
| 	} | 	} | ||||||
| 	if err = rows.Err(); err != nil { | 	if err = rows.Err(); err != nil { | ||||||
| @ -268,11 +280,16 @@ func (m *WebsiteModel) GetAll() ([]Website, error) { | |||||||
| 	var websites []Website | 	var websites []Website | ||||||
| 	for rows.Next() { | 	for rows.Next() { | ||||||
| 		var w Website | 		var w Website | ||||||
| 		err := rows.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created, | 		var u string | ||||||
|  | 		err := rows.Scan(&w.ID, &w.ShortId, &w.Name, &u, &w.AuthorName, &w.UserId, &w.Created, | ||||||
| 			&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive) | 			&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
|  | 		w.Url, err = url.Parse(u) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
| 		websites = append(websites, w) | 		websites = append(websites, w) | ||||||
| 	} | 	} | ||||||
| 	if err = rows.Err(); err != nil { | 	if err = rows.Err(); err != nil { | ||||||
|  | |||||||
| @ -8,51 +8,52 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var EmailRX = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$") | var EmailRX = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$") | ||||||
|  | var WebRX = regexp.MustCompile("^https?:\\/\\/") | ||||||
| 
 | 
 | ||||||
| type Validator struct { | type Validator struct { | ||||||
|     NonFieldErrors []string | 	NonFieldErrors []string | ||||||
|     FieldErrors map[string]string | 	FieldErrors    map[string]string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (v *Validator) Valid() bool { | func (v *Validator) Valid() bool { | ||||||
|     return len(v.FieldErrors) == 0 && len(v.NonFieldErrors) == 0 | 	return len(v.FieldErrors) == 0 && len(v.NonFieldErrors) == 0 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (v *Validator) AddFieldError(key, message string) { | func (v *Validator) AddFieldError(key, message string) { | ||||||
|     if v.FieldErrors == nil { | 	if v.FieldErrors == nil { | ||||||
|         v.FieldErrors = make(map[string]string) | 		v.FieldErrors = make(map[string]string) | ||||||
|     } | 	} | ||||||
|     if _, exists := v.FieldErrors[key]; !exists { | 	if _, exists := v.FieldErrors[key]; !exists { | ||||||
|         v.FieldErrors[key] = message | 		v.FieldErrors[key] = message | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (v *Validator) AddNonFieldError(message string) { | func (v *Validator) AddNonFieldError(message string) { | ||||||
|     v.NonFieldErrors = append(v.NonFieldErrors, message) | 	v.NonFieldErrors = append(v.NonFieldErrors, message) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (v *Validator) CheckField(ok bool, key, message string) { | func (v *Validator) CheckField(ok bool, key, message string) { | ||||||
|     if !ok { | 	if !ok { | ||||||
|         v.AddFieldError(key, message) | 		v.AddFieldError(key, message) | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NotBlank(value string) bool { | func NotBlank(value string) bool { | ||||||
|     return strings.TrimSpace(value) != "" | 	return strings.TrimSpace(value) != "" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func MaxChars(value string, n int) bool { | func MaxChars(value string, n int) bool { | ||||||
|     return utf8.RuneCountInString(value) <= n | 	return utf8.RuneCountInString(value) <= n | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func PermittedValue[T comparable](value T, permittedValues ...T) bool { | func PermittedValue[T comparable](value T, permittedValues ...T) bool { | ||||||
|     return slices.Contains(permittedValues, value) | 	return slices.Contains(permittedValues, value) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func MinChars(value string, n int) bool { | func MinChars(value string, n int) bool { | ||||||
|     return utf8.RuneCountInString(value) >= n | 	return utf8.RuneCountInString(value) >= n | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func Matches(value string, rx *regexp.Regexp) bool { | func Matches(value string, rx *regexp.Regexp) bool { | ||||||
|     return rx.MatchString(value) | 	return rx.MatchString(value) | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								migrations/000005_normalize_site_urls.down.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								migrations/000005_normalize_site_urls.down.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | UPDATE websites SET SiteUrl = substr(SiteUrl, 8) WHERE substr(SiteUrl, 1, 4) = 'http'; | ||||||
							
								
								
									
										1
									
								
								migrations/000005_normalize_site_urls.up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								migrations/000005_normalize_site_urls.up.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | UPDATE websites SET SiteUrl = 'http://' || SiteUrl WHERE substr(SiteUrl, 1, 4) <> 'http'; | ||||||
| @ -58,10 +58,17 @@ div#dashboard { | |||||||
| div#dashboard nav { | div#dashboard nav { | ||||||
|   flex: 1 1 25%; |   flex: 1 1 25%; | ||||||
|   margin-top: 2rem; |   margin-top: 2rem; | ||||||
|  |   min-width: 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| div#dashboard > div { | div#dashboard > div { | ||||||
|   flex: 10 1 40%; |   flex: 10 1 40%; | ||||||
|  |   min-width: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | div > pre { | ||||||
|  |     max-width: 100%; | ||||||
|  |     overflow: auto; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| main nav ul { | main nav ul { | ||||||
|  | |||||||
							
								
								
									
										177
									
								
								ui/static/js/guestbook.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								ui/static/js/guestbook.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,177 @@ | |||||||
|  | class GuestbookForm extends HTMLElement { | ||||||
|  |     static get observedAttributes() { | ||||||
|  |         return ['guestbook']; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     constructor() { | ||||||
|  |         super(); | ||||||
|  |         this.attachShadow({ mode: 'open' }); | ||||||
|  |         this._guestbook = this.getAttribute('guestbook') || ''; | ||||||
|  |         this._postUrl = `${this._guestbook}/comments/create/remote` | ||||||
|  |         this.render(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     attributeChangedCallback(name, oldValue, newValue) { | ||||||
|  |         if (name === 'guestbook') { | ||||||
|  |             this._guestbook = newValue; | ||||||
|  |             this.render(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     render() { | ||||||
|  |         this.shadowRoot.innerHTML = ` | ||||||
|  |       <style> | ||||||
|  |         form div { | ||||||
|  |           margin-bottom: 0.75em; | ||||||
|  |         } | ||||||
|  |         label { | ||||||
|  |           display: block; | ||||||
|  |           font-weight: bold; | ||||||
|  |           margin-bottom: 0.25em; | ||||||
|  |         } | ||||||
|  |         input[type="text"], textarea { | ||||||
|  |           width: 100%; | ||||||
|  |           box-sizing: border-box; | ||||||
|  |         } | ||||||
|  |         input[type="submit"] { | ||||||
|  |           font-size: 1em; | ||||||
|  |           padding: 0.5em 1em; | ||||||
|  |         } | ||||||
|  |       </style> | ||||||
|  |       <form action="${this._postUrl}" method="post"> | ||||||
|  |         <div> | ||||||
|  |           <label for="authorname">Name</label> | ||||||
|  |           <input type="text" name="authorname" id="authorname"/> | ||||||
|  |         </div> | ||||||
|  |         <div> | ||||||
|  |           <label for="authoremail">Email (Optional)</label> | ||||||
|  |           <input type="text" name="authoremail" id="authoremail"/> | ||||||
|  |         </div> | ||||||
|  |         <div> | ||||||
|  |           <label for="authorsite">Site Url (Optional)</label> | ||||||
|  |           <input type="text" name="authorsite" id="authorsite"/> | ||||||
|  |         </div> | ||||||
|  |         <div> | ||||||
|  |           <label for="content">Comment</label> | ||||||
|  |           <textarea name="content" id="content"></textarea> | ||||||
|  |         </div> | ||||||
|  |         <div> | ||||||
|  |           <input type="hidden" value="${window.location.pathname}" name="redirect" id="redirect" /> | ||||||
|  |         </div> | ||||||
|  |         <div> | ||||||
|  |           <input type="submit" value="Submit"/> | ||||||
|  |         </div> | ||||||
|  |       </form> | ||||||
|  |     `;
 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class CommentList extends HTMLElement { | ||||||
|  |     static get observedAttributes() { | ||||||
|  |         return ['guestbook']; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     constructor() { | ||||||
|  |         super(); | ||||||
|  |         this.attachShadow({ mode: 'open' }); | ||||||
|  |         this.comments = []; | ||||||
|  |         this.loading = false; | ||||||
|  |         this.error = null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     connectedCallback() { | ||||||
|  |         if (this.hasAttribute('guestbook')) { | ||||||
|  |             this.fetchComments(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     attributeChangedCallback(name, oldValue, newValue) { | ||||||
|  |         if (name === 'guestbook' && oldValue !== newValue) { | ||||||
|  |             this.fetchComments(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fetchComments() { | ||||||
|  |         const guestbook = this.getAttribute('guestbook'); | ||||||
|  |         if (!guestbook) return; | ||||||
|  |         this.loading = true; | ||||||
|  |         this.error = null; | ||||||
|  |         this.render(); | ||||||
|  | 
 | ||||||
|  |         const commentsUrl = `${guestbook}/comments` | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             const response = await fetch(commentsUrl); | ||||||
|  |             if (!response.ok) throw new Error(`HTTP error: ${response.status}`); | ||||||
|  |             const data = await response.json(); | ||||||
|  |             this.comments = Array.isArray(data) ? data : []; | ||||||
|  |             this.loading = false; | ||||||
|  |             this.render(); | ||||||
|  |         } catch (err) { | ||||||
|  |             this.error = err.message; | ||||||
|  |             this.loading = false; | ||||||
|  |             this.render(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     formatDate(isoString) { | ||||||
|  |         if (!isoString) return ''; | ||||||
|  |         const date = new Date(isoString); | ||||||
|  |         return date.toLocaleString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     render() { | ||||||
|  |         this.shadowRoot.innerHTML = ` | ||||||
|  |       <style> | ||||||
|  |         .comment-list { | ||||||
|  |           font-family: Arial, sans-serif; | ||||||
|  |           border: 1px solid #ddd; | ||||||
|  |           border-radius: 6px; | ||||||
|  |           padding: 1em; | ||||||
|  |           background: #fafafa; | ||||||
|  |         } | ||||||
|  |         .comment { | ||||||
|  |           border-bottom: 1px solid #eee; | ||||||
|  |           padding: 0.7em 0; | ||||||
|  |         } | ||||||
|  |         .comment:last-child { | ||||||
|  |           border-bottom: none; | ||||||
|  |         } | ||||||
|  |         .author { | ||||||
|  |           font-weight: bold; | ||||||
|  |           margin-right: 1em; | ||||||
|  |         } | ||||||
|  |         .timestamp { | ||||||
|  |           color: #888; | ||||||
|  |           font-size: 0.85em; | ||||||
|  |         } | ||||||
|  |         .text { | ||||||
|  |           margin: 0.2em 0 0 0; | ||||||
|  |         } | ||||||
|  |         .error { | ||||||
|  |           color: red; | ||||||
|  |         } | ||||||
|  |       </style> | ||||||
|  |       <div class="comment-list"> | ||||||
|  |         ${this.loading | ||||||
|  |                 ? `<div>Loading comments...</div>` | ||||||
|  |                 : this.error | ||||||
|  |                     ? `<div class="error">Error: ${this.error}</div>` | ||||||
|  |                     : this.comments.length === 0 | ||||||
|  |                         ? `<div>No comments found.</div>` | ||||||
|  |                         : this.comments.map(comment => ` | ||||||
|  |                   <div class="comment"> | ||||||
|  |                     <span class="author">${comment.AuthorName || 'Unknown Author'}</span> | ||||||
|  |                     <span class="timestamp">${this.formatDate(comment.Created)}</span> | ||||||
|  |                     <div class="text">${comment.CommentText || ''}</div> | ||||||
|  |                   </div> | ||||||
|  |                 `).join('')
 | ||||||
|  |             } | ||||||
|  |       </div> | ||||||
|  |     `;
 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | customElements.define('guestbook-form', GuestbookForm); | ||||||
|  | customElements.define('guestbook-comments', CommentList); | ||||||
|  | 
 | ||||||
							
								
								
									
										13
									
								
								ui/static/js/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								ui/static/js/main.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | 
 | ||||||
|  | const convertDates = () => { | ||||||
|  |     const dates = document.getElementsByTagName("time") | ||||||
|  |     for (let i = 0; i < dates.length; i++) { | ||||||
|  |         const e = dates.item(i) | ||||||
|  |         const d = e.attributes.getNamedItem("datetime").value | ||||||
|  |         const dt = new Date(Date.parse(d)) | ||||||
|  |         const localtime = dt.toLocaleString("en-US", { "year": "numeric", "month": "short", "day": "numeric", "hour": "numeric", "minute": "numeric", "timeZoneName": "short"}) | ||||||
|  |         e.innerText = localtime | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | convertDates() | ||||||
| @ -6,87 +6,85 @@ import "fmt" | |||||||
| import "strings" | import "strings" | ||||||
| 
 | 
 | ||||||
| type CommonData struct { | type CommonData struct { | ||||||
|     CurrentYear int | 	CurrentYear     int | ||||||
|     Flash string | 	Flash           string | ||||||
|     IsAuthenticated bool | 	IsAuthenticated bool | ||||||
|     CSRFToken string | 	CSRFToken       string | ||||||
|     CurrentUser *models.User | 	CurrentUser     *models.User | ||||||
|     IsHtmx bool | 	IsHtmx          bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func shortIdToSlug(shortId uint64) string { | func shortIdToSlug(shortId uint64) string { | ||||||
|     return strconv.FormatUint(shortId, 36) | 	return strconv.FormatUint(shortId, 36) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func slugToShortId(slug string) uint64 { | func slugToShortId(slug string) uint64 { | ||||||
|     id, _ := strconv.ParseUint(slug, 36, 64) | 	id, _ := strconv.ParseUint(slug, 36, 64) | ||||||
|     return id | 	return id | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func externalUrl(url string) string { | func externalUrl(url string) string { | ||||||
|     if !strings.HasPrefix(url, "http") { | 	if !strings.HasPrefix(url, "http") { | ||||||
|         return "http://" + url | 		return "http://" + url | ||||||
|     } | 	} | ||||||
|     return url | 	return url | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| templ commonHeader() { | templ commonHeader() { | ||||||
|     <header> | 	<header> | ||||||
|         <h1><a href="/">webweav.ing</a></h1> | 		<h1><a href="/">webweav.ing</a></h1> | ||||||
|     </header> | 	</header> | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| templ topNav(data CommonData) { | templ topNav(data CommonData) { | ||||||
|     {{ hxHeaders := fmt.Sprintf("{\"X-CSRF-Token\": \"%s\"}", data.CSRFToken) }} | 	{{ hxHeaders := fmt.Sprintf("{\"X-CSRF-Token\": \"%s\"}", data.CSRFToken) }} | ||||||
|     <nav> | 	<nav> | ||||||
|         <div> | 		<div> | ||||||
|             if data.IsAuthenticated { | 			if data.IsAuthenticated { | ||||||
|                 Welcome, { data.CurrentUser.Username } | 				Welcome, { data.CurrentUser.Username } | ||||||
|             } | 			} | ||||||
|         </div> | 		</div> | ||||||
|         <div> | 		<div> | ||||||
|             if data.IsAuthenticated { | 			if data.IsAuthenticated { | ||||||
|                 <a href="/guestbooks">All Guestbooks</a> | | 				<a href="/guestbooks">All Guestbooks</a> | | ||||||
|                 <a href="/websites">My Websites</a> |  | 				<a href="/websites">My Websites</a> |  | ||||||
|                 <a href="/users/settings">Settings</a> |  | 				<a href="/users/settings">Settings</a> |  | ||||||
|                 <a href="#" hx-post="/users/logout" hx-headers={ hxHeaders }>Logout</a> | 				<a href="#" hx-post="/users/logout" hx-headers={ hxHeaders }>Logout</a> | ||||||
|             } else { | 			} else { | ||||||
|                 <a href="/users/register">Create an Account</a> |  | 				<a href="/users/register">Create an Account</a> |  | ||||||
|                 <a href="/users/login">Login</a> | 				<a href="/users/login">Login</a> | ||||||
|             } | 			} | ||||||
|         </div> | 		</div> | ||||||
|     </nav> | 	</nav> | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| templ commonFooter() { | templ commonFooter() { | ||||||
|     <footer> | 	<footer> | ||||||
|         <p>A <a href="https://32bit.cafe">32bit.cafe</a> Project</p> | 		<p>A <a href="https://32bit.cafe">32bit.cafe</a> Project</p> | ||||||
|     </footer> | 	</footer> | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| templ base(title string, data CommonData) { | templ base(title string, data CommonData) { | ||||||
|     <!DOCTYPE html> | 	<!DOCTYPE html> | ||||||
|     <html lang="en"> | 	<html lang="en"> | ||||||
|         <head> | 		<head> | ||||||
|             <title>{ title } - webweav.ing</title> | 			<title>{ title } - webweav.ing</title> | ||||||
|             <meta charset="UTF-8"> | 			<meta charset="UTF-8"/> | ||||||
|             <meta name="viewport" content="width=device-width, initial-scale=1"> | 			<meta name="viewport" content="width=device-width, initial-scale=1"/> | ||||||
|             <link href="/static/css/classless.min.css" rel="stylesheet"> | 			<link href="/static/css/classless.min.css" rel="stylesheet"/> | ||||||
|             <link href="/static/css/style.css" rel="stylesheet"> | 			<link href="/static/css/style.css" rel="stylesheet"/> | ||||||
|             <script src="/static/js/htmx.min.js"></script> | 			<script src="/static/js/htmx.min.js"></script> | ||||||
|         </head> | 		</head> | ||||||
|         <body> | 		<body> | ||||||
|             @commonHeader() | 			@commonHeader() | ||||||
|             @topNav(data) | 			@topNav(data) | ||||||
|             <main> | 			<main> | ||||||
|                 if data.Flash != "" { | 				if data.Flash != "" { | ||||||
|                     <div class="flash">{ data.Flash }</div> | 					<div class="flash">{ data.Flash }</div> | ||||||
|                 } | 				} | ||||||
|                 { children... } | 				{ children... } | ||||||
|             </main> | 			</main> | ||||||
|             @commonFooter() | 			@commonFooter() | ||||||
|         </body> | 		</body> | ||||||
|     </html> | 	</html> | ||||||
| } | } | ||||||
| 
 |  | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ type CommonData struct { | |||||||
| 	CSRFToken       string | 	CSRFToken       string | ||||||
| 	CurrentUser     *models.User | 	CurrentUser     *models.User | ||||||
| 	IsHtmx          bool | 	IsHtmx          bool | ||||||
|  | 	RootUrl         string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func shortIdToSlug(shortId uint64) string { | func shortIdToSlug(shortId uint64) string { | ||||||
| @ -101,7 +102,7 @@ func topNav(data CommonData) templ.Component { | |||||||
| 			var templ_7745c5c3_Var3 string | 			var templ_7745c5c3_Var3 string | ||||||
| 			templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.CurrentUser.Username) | 			templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.CurrentUser.Username) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 44, Col: 52} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 44, Col: 40} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| @ -120,7 +121,7 @@ func topNav(data CommonData) templ.Component { | |||||||
| 			var templ_7745c5c3_Var4 string | 			var templ_7745c5c3_Var4 string | ||||||
| 			templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(hxHeaders) | 			templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(hxHeaders) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 52, Col: 74} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 52, Col: 62} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| @ -201,7 +202,7 @@ func base(title string, data CommonData) templ.Component { | |||||||
| 		var templ_7745c5c3_Var7 string | 		var templ_7745c5c3_Var7 string | ||||||
| 		templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(title) | 		templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(title) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 72, Col: 26} | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 71, Col: 17} | ||||||
| 		} | 		} | ||||||
| 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| @ -231,7 +232,7 @@ func base(title string, data CommonData) templ.Component { | |||||||
| 			var templ_7745c5c3_Var8 string | 			var templ_7745c5c3_Var8 string | ||||||
| 			templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(data.Flash) | 			templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(data.Flash) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 84, Col: 51} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/common.templ`, Line: 83, Col: 36} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ templ GuestbookDashboardCommentsView(title string, data CommonData, website mode | |||||||
| 		<div id="dashboard"> | 		<div id="dashboard"> | ||||||
| 			@wSidebar(website) | 			@wSidebar(website) | ||||||
| 			<div> | 			<div> | ||||||
| 				<h1>Comments on { website.SiteUrl }</h1> | 				<h1>Comments on { website.Name }</h1> | ||||||
| 				<hr/> | 				<hr/> | ||||||
| 				if len(comments) == 0 { | 				if len(comments) == 0 { | ||||||
| 					<p>No comments yet!</p> | 					<p>No comments yet!</p> | ||||||
| @ -61,7 +61,7 @@ templ GuestbookDashboardCommentView(data CommonData, w models.Website, c models. | |||||||
| 
 | 
 | ||||||
| templ commentForm(form forms.CommentCreateForm) { | templ commentForm(form forms.CommentCreateForm) { | ||||||
| 	<div> | 	<div> | ||||||
| 		<label for="authorname">Name: </label> | 		<label for="authorname">Name</label> | ||||||
| 		{{ error, exists := form.FieldErrors["authorName"] }} | 		{{ error, exists := form.FieldErrors["authorName"] }} | ||||||
| 		if exists { | 		if exists { | ||||||
| 			<label class="error">{ error }</label> | 			<label class="error">{ error }</label> | ||||||
| @ -69,7 +69,7 @@ templ commentForm(form forms.CommentCreateForm) { | |||||||
| 		<input type="text" name="authorname" id="authorname"/> | 		<input type="text" name="authorname" id="authorname"/> | ||||||
| 	</div> | 	</div> | ||||||
| 	<div> | 	<div> | ||||||
| 		<label for="authoremail">Email: </label> | 		<label for="authoremail">Email (Optional) </label> | ||||||
| 		{{ error, exists = form.FieldErrors["authorEmail"] }} | 		{{ error, exists = form.FieldErrors["authorEmail"] }} | ||||||
| 		if exists { | 		if exists { | ||||||
| 			<label class="error">{ error }</label> | 			<label class="error">{ error }</label> | ||||||
| @ -77,7 +77,7 @@ templ commentForm(form forms.CommentCreateForm) { | |||||||
| 		<input type="text" name="authoremail" id="authoremail"/> | 		<input type="text" name="authoremail" id="authoremail"/> | ||||||
| 	</div> | 	</div> | ||||||
| 	<div> | 	<div> | ||||||
| 		<label for="authorsite">Site Url: </label> | 		<label for="authorsite">Site Url (Optional) </label> | ||||||
| 		{{ error, exists = form.FieldErrors["authorSite"] }} | 		{{ error, exists = form.FieldErrors["authorSite"] }} | ||||||
| 		if exists { | 		if exists { | ||||||
| 			<label class="error">{ error }</label> | 			<label class="error">{ error }</label> | ||||||
| @ -85,7 +85,7 @@ templ commentForm(form forms.CommentCreateForm) { | |||||||
| 		<input type="text" name="authorsite" id="authorsite"/> | 		<input type="text" name="authorsite" id="authorsite"/> | ||||||
| 	</div> | 	</div> | ||||||
| 	<div> | 	<div> | ||||||
| 		<label for="content">Comment: </label> | 		<label for="content">Comment</label> | ||||||
| 		{{ error, exists = form.FieldErrors["content"] }} | 		{{ error, exists = form.FieldErrors["content"] }} | ||||||
| 		if exists { | 		if exists { | ||||||
| 			<label class="error">{ error }</label> | 			<label class="error">{ error }</label> | ||||||
| @ -106,11 +106,13 @@ templ GuestbookView(title string, data CommonData, website models.Website, guest | |||||||
| 			<head> | 			<head> | ||||||
| 				<title>{ title }</title> | 				<title>{ title }</title> | ||||||
| 				<link href="/static/css/classless.min.css" rel="stylesheet"/> | 				<link href="/static/css/classless.min.css" rel="stylesheet"/> | ||||||
|  | 				<script src="/static/js/main.js" defer></script> | ||||||
| 			</head> | 			</head> | ||||||
| 			<body> | 			<body> | ||||||
| 				<main> | 				<main> | ||||||
| 					<div> | 					<div> | ||||||
| 						<h1>Guestbook for { website.Name }</h1> | 						<h1>Guestbook for { website.Name }</h1> | ||||||
|  | 						{ data.Flash } | ||||||
| 						<form action={ templ.URL(postUrl) } method="post"> | 						<form action={ templ.URL(postUrl) } method="post"> | ||||||
| 							<input type="hidden" name="csrf_token" value={ data.CSRFToken }/> | 							<input type="hidden" name="csrf_token" value={ data.CSRFToken }/> | ||||||
| 							@commentForm(form) | 							@commentForm(form) | ||||||
| @ -122,8 +124,14 @@ templ GuestbookView(title string, data CommonData, website models.Website, guest | |||||||
| 						} | 						} | ||||||
| 						for _, c := range comments { | 						for _, c := range comments { | ||||||
| 							<div> | 							<div> | ||||||
| 								<h3>{ c.AuthorName }</h3> | 								<h3> | ||||||
| 								{ c.Created.Format("01-02-2006 03:04PM") } | 									if c.AuthorSite != "" { | ||||||
|  | 										<a href={ templ.URL(externalUrl(c.AuthorSite)) } target="_blank">{ c.AuthorName }</a> | ||||||
|  | 									} else { | ||||||
|  | 										{ c.AuthorName } | ||||||
|  | 									} | ||||||
|  | 								</h3> | ||||||
|  | 								<time datetime={ c.Created.Format(time.RFC3339) }>{ c.Created.Format("01-02-2006 03:04PM") }</time> | ||||||
| 								<p> | 								<p> | ||||||
| 									{ c.CommentText } | 									{ c.CommentText } | ||||||
| 								</p> | 								</p> | ||||||
| @ -136,21 +144,6 @@ templ GuestbookView(title string, data CommonData, website models.Website, guest | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| templ CreateGuestbookComment(title string, data CommonData, website models.Website, guestbook models.Guestbook, form forms.CommentCreateForm) { |  | ||||||
| 	{{ postUrl := fmt.Sprintf("/websites/%s/guestbook/comments/create", shortIdToSlug(website.ShortId)) }} |  | ||||||
| 	if data.IsHtmx { |  | ||||||
| 		<form hx-post={ postUrl } hx-target="closest div"> |  | ||||||
| 			@commentForm(form) |  | ||||||
| 		</form> |  | ||||||
| 	} else { |  | ||||||
| 		@base(title, data) { |  | ||||||
| 			<form action={ templ.URL(postUrl) } method="post"> |  | ||||||
| 				@commentForm(form) |  | ||||||
| 			</form> |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| templ settingRadio(selected bool, name, id, value string) { | templ settingRadio(selected bool, name, id, value string) { | ||||||
| 	<input type="radio" name={ name } id={ id } value={ value } selected?={ selected }/> | 	<input type="radio" name={ name } id={ id } value={ value } selected?={ selected }/> | ||||||
| } | } | ||||||
| @ -211,6 +204,22 @@ templ GuestbookSettingsView(data CommonData, website models.Website) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | templ EmbeddableGuestbookCommentForm(data CommonData, w models.Website, f forms.CommentCreateForm) { | ||||||
|  | 	{{ postUrl := fmt.Sprintf("/websites/%s/guestbook/comments/create?headless=true", shortIdToSlug(w.ShortId)) }} | ||||||
|  | 	<html> | ||||||
|  | 		<head> | ||||||
|  | 			<link href="/static/css/classless.min.css" rel="stylesheet"/> | ||||||
|  | 		</head> | ||||||
|  | 		<body> | ||||||
|  | 			{ data.Flash } | ||||||
|  | 			<form action={ templ.URL(postUrl) } method="post"> | ||||||
|  | 				<input type="hidden" name="csrf_token" value={ data.CSRFToken }/> | ||||||
|  | 				@commentForm(f) | ||||||
|  | 			</form> | ||||||
|  | 		</body> | ||||||
|  | 	</html> | ||||||
|  | } | ||||||
|  | 
 | ||||||
| templ AllGuestbooksView(data CommonData, websites []models.Website) { | templ AllGuestbooksView(data CommonData, websites []models.Website) { | ||||||
| 	@base("All Guestbooks", data) { | 	@base("All Guestbooks", data) { | ||||||
| 		<div> | 		<div> | ||||||
| @ -229,3 +238,35 @@ templ AllGuestbooksView(data CommonData, websites []models.Website) { | |||||||
| 		</div> | 		</div> | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | templ GuestbookCommentCreateRemoteErrorView(url, err string) { | ||||||
|  | 	<html> | ||||||
|  | 		<head> | ||||||
|  | 			<meta http-equiv="refresh" content={ fmt.Sprintf("3; url='%s'", templ.URL(externalUrl(url))) }/> | ||||||
|  | 		</head> | ||||||
|  | 		<body> | ||||||
|  | 			<p> | ||||||
|  | 				An error occurred while posting comment. { err }. Redirecting. | ||||||
|  | 			</p> | ||||||
|  | 			<p> | ||||||
|  | 				<a href={ templ.URL(url) }>Redirect</a> | ||||||
|  | 			</p> | ||||||
|  | 		</body> | ||||||
|  | 	</html> | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | templ GuestbookCommentCreateRemoteSuccessView(url string) { | ||||||
|  | 	<html> | ||||||
|  | 		<head> | ||||||
|  | 			<meta http-equiv="refresh" content={ fmt.Sprintf("3; url='%s'", templ.URL(externalUrl(url))) }/> | ||||||
|  | 		</head> | ||||||
|  | 		<body> | ||||||
|  | 			<p> | ||||||
|  | 				Comment successfully posted. Redirecting. | ||||||
|  | 			</p> | ||||||
|  | 			<p> | ||||||
|  | 				<a href={ templ.URL(url) }>Redirect</a> | ||||||
|  | 			</p> | ||||||
|  | 		</body> | ||||||
|  | 	</html> | ||||||
|  | } | ||||||
|  | |||||||
| @ -59,9 +59,9 @@ func GuestbookDashboardCommentsView(title string, data CommonData, website model | |||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			var templ_7745c5c3_Var3 string | 			var templ_7745c5c3_Var3 string | ||||||
| 			templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(website.SiteUrl) | 			templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 13, Col: 37} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 13, Col: 34} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| @ -326,7 +326,7 @@ func commentForm(form forms.CommentCreateForm) templ.Component { | |||||||
| 			templ_7745c5c3_Var16 = templ.NopComponent | 			templ_7745c5c3_Var16 = templ.NopComponent | ||||||
| 		} | 		} | ||||||
| 		ctx = templ.ClearChildren(ctx) | 		ctx = templ.ClearChildren(ctx) | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<div><label for=\"authorname\">Name: </label>") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<div><label for=\"authorname\">Name</label>") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| @ -350,7 +350,7 @@ func commentForm(form forms.CommentCreateForm) templ.Component { | |||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<input type=\"text\" name=\"authorname\" id=\"authorname\"></div><div><label for=\"authoremail\">Email: </label>") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<input type=\"text\" name=\"authorname\" id=\"authorname\"></div><div><label for=\"authoremail\">Email (Optional) </label>") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| @ -374,7 +374,7 @@ func commentForm(form forms.CommentCreateForm) templ.Component { | |||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<input type=\"text\" name=\"authoremail\" id=\"authoremail\"></div><div><label for=\"authorsite\">Site Url: </label>") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<input type=\"text\" name=\"authoremail\" id=\"authoremail\"></div><div><label for=\"authorsite\">Site Url (Optional) </label>") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| @ -398,7 +398,7 @@ func commentForm(form forms.CommentCreateForm) templ.Component { | |||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<input type=\"text\" name=\"authorsite\" id=\"authorsite\"></div><div><label for=\"content\">Comment: </label>") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<input type=\"text\" name=\"authorsite\" id=\"authorsite\"></div><div><label for=\"content\">Comment</label>") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| @ -471,42 +471,55 @@ func GuestbookView(title string, data CommonData, website models.Website, guestb | |||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</title><link href=\"/static/css/classless.min.css\" rel=\"stylesheet\"></head><body><main><div><h1>Guestbook for ") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</title><link href=\"/static/css/classless.min.css\" rel=\"stylesheet\"><script src=\"/static/js/main.js\" defer></script></head><body><main><div><h1>Guestbook for ") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			var templ_7745c5c3_Var23 string | 			var templ_7745c5c3_Var23 string | ||||||
| 			templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name) | 			templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 113, Col: 38} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 114, Col: 38} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "</h1><form action=\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "</h1>") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			var templ_7745c5c3_Var24 templ.SafeURL = templ.URL(postUrl) | 			var templ_7745c5c3_Var24 string | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var24))) | 			templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(data.Flash) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 115, Col: 18} | ||||||
|  | 			} | ||||||
|  | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "\" method=\"post\"><input type=\"hidden\" name=\"csrf_token\" value=\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<form action=\"") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			var templ_7745c5c3_Var25 string | 			var templ_7745c5c3_Var25 templ.SafeURL = templ.URL(postUrl) | ||||||
| 			templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(data.CSRFToken) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var25))) | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 115, Col: 68} |  | ||||||
| 			} |  | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) |  | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "\">") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "\" method=\"post\"><input type=\"hidden\" name=\"csrf_token\" value=\"") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			var templ_7745c5c3_Var26 string | ||||||
|  | 			templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(data.CSRFToken) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 117, Col: 68} | ||||||
|  | 			} | ||||||
|  | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "\">") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| @ -514,155 +527,104 @@ func GuestbookView(title string, data CommonData, website models.Website, guestb | |||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "</form></div><div id=\"comments\">") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "</form></div><div id=\"comments\">") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			if len(comments) == 0 { | 			if len(comments) == 0 { | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "<p>No comments yet!</p>") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "<p>No comments yet!</p>") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			for _, c := range comments { | 			for _, c := range comments { | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "<div><h3>") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "<div><h3>") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				var templ_7745c5c3_Var26 string | 				if c.AuthorSite != "" { | ||||||
| 				templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(c.AuthorName) | 					templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "<a href=\"") | ||||||
| 				if templ_7745c5c3_Err != nil { | 					if templ_7745c5c3_Err != nil { | ||||||
| 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 125, Col: 26} | 						return templ_7745c5c3_Err | ||||||
|  | 					} | ||||||
|  | 					var templ_7745c5c3_Var27 templ.SafeURL = templ.URL(externalUrl(c.AuthorSite)) | ||||||
|  | 					_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var27))) | ||||||
|  | 					if templ_7745c5c3_Err != nil { | ||||||
|  | 						return templ_7745c5c3_Err | ||||||
|  | 					} | ||||||
|  | 					templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "\" target=\"_blank\">") | ||||||
|  | 					if templ_7745c5c3_Err != nil { | ||||||
|  | 						return templ_7745c5c3_Err | ||||||
|  | 					} | ||||||
|  | 					var templ_7745c5c3_Var28 string | ||||||
|  | 					templ_7745c5c3_Var28, 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: 129, Col: 89} | ||||||
|  | 					} | ||||||
|  | 					_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) | ||||||
|  | 					if templ_7745c5c3_Err != nil { | ||||||
|  | 						return templ_7745c5c3_Err | ||||||
|  | 					} | ||||||
|  | 					templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "</a>") | ||||||
|  | 					if templ_7745c5c3_Err != nil { | ||||||
|  | 						return templ_7745c5c3_Err | ||||||
|  | 					} | ||||||
|  | 				} else { | ||||||
|  | 					var templ_7745c5c3_Var29 string | ||||||
|  | 					templ_7745c5c3_Var29, 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: 131, Col: 24} | ||||||
|  | 					} | ||||||
|  | 					_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) | ||||||
|  | 					if templ_7745c5c3_Err != nil { | ||||||
|  | 						return templ_7745c5c3_Err | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "</h3><time datetime=\"") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "</h3>") | 				var templ_7745c5c3_Var30 string | ||||||
|  | 				templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(c.Created.Format(time.RFC3339)) | ||||||
|  | 				if templ_7745c5c3_Err != nil { | ||||||
|  | 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 134, Col: 55} | ||||||
|  | 				} | ||||||
|  | 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				var templ_7745c5c3_Var27 string | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "\">") | ||||||
| 				templ_7745c5c3_Var27, 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: 126, Col: 48} |  | ||||||
| 				} |  | ||||||
| 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) |  | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "<p>") | 				var templ_7745c5c3_Var31 string | ||||||
|  | 				templ_7745c5c3_Var31, 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: 134, Col: 98} | ||||||
|  | 				} | ||||||
|  | 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				var templ_7745c5c3_Var28 string | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</time><p>") | ||||||
| 				templ_7745c5c3_Var28, 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: 128, Col: 24} |  | ||||||
| 				} |  | ||||||
| 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) |  | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</p></div>") | 				var templ_7745c5c3_Var32 string | ||||||
|  | 				templ_7745c5c3_Var32, 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: 136, Col: 24} | ||||||
|  | 				} | ||||||
|  | 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) | ||||||
|  | 				if templ_7745c5c3_Err != nil { | ||||||
|  | 					return templ_7745c5c3_Err | ||||||
|  | 				} | ||||||
|  | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "</p></div>") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "</div></main></body></html>") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "</div></main></body></html>") | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return nil |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func CreateGuestbookComment(title string, data CommonData, website models.Website, guestbook models.Guestbook, form forms.CommentCreateForm) 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_Var29 := templ.GetChildren(ctx) |  | ||||||
| 		if templ_7745c5c3_Var29 == nil { |  | ||||||
| 			templ_7745c5c3_Var29 = templ.NopComponent |  | ||||||
| 		} |  | ||||||
| 		ctx = templ.ClearChildren(ctx) |  | ||||||
| 		postUrl := fmt.Sprintf("/websites/%s/guestbook/comments/create", shortIdToSlug(website.ShortId)) |  | ||||||
| 		if data.IsHtmx { |  | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "<form hx-post=\"") |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			var templ_7745c5c3_Var30 string |  | ||||||
| 			templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(postUrl) |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 142, Col: 25} |  | ||||||
| 			} |  | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "\" hx-target=\"closest div\">") |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			templ_7745c5c3_Err = commentForm(form).Render(ctx, templ_7745c5c3_Buffer) |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</form>") |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			templ_7745c5c3_Var31 := 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, 54, "<form action=\"") |  | ||||||
| 				if templ_7745c5c3_Err != nil { |  | ||||||
| 					return templ_7745c5c3_Err |  | ||||||
| 				} |  | ||||||
| 				var templ_7745c5c3_Var32 templ.SafeURL = templ.URL(postUrl) |  | ||||||
| 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var32))) |  | ||||||
| 				if templ_7745c5c3_Err != nil { |  | ||||||
| 					return templ_7745c5c3_Err |  | ||||||
| 				} |  | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "\" method=\"post\">") |  | ||||||
| 				if templ_7745c5c3_Err != nil { |  | ||||||
| 					return templ_7745c5c3_Err |  | ||||||
| 				} |  | ||||||
| 				templ_7745c5c3_Err = commentForm(form).Render(ctx, templ_7745c5c3_Buffer) |  | ||||||
| 				if templ_7745c5c3_Err != nil { |  | ||||||
| 					return templ_7745c5c3_Err |  | ||||||
| 				} |  | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "</form>") |  | ||||||
| 				if templ_7745c5c3_Err != nil { |  | ||||||
| 					return templ_7745c5c3_Err |  | ||||||
| 				} |  | ||||||
| 				return nil |  | ||||||
| 			}) |  | ||||||
| 			templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var31), templ_7745c5c3_Buffer) |  | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| @ -692,56 +654,56 @@ func settingRadio(selected bool, name, id, value string) templ.Component { | |||||||
| 			templ_7745c5c3_Var33 = templ.NopComponent | 			templ_7745c5c3_Var33 = templ.NopComponent | ||||||
| 		} | 		} | ||||||
| 		ctx = templ.ClearChildren(ctx) | 		ctx = templ.ClearChildren(ctx) | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "<input type=\"radio\" name=\"") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "<input type=\"radio\" name=\"") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		var templ_7745c5c3_Var34 string | 		var templ_7745c5c3_Var34 string | ||||||
| 		templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(name) | 		templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(name) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 155, Col: 32} | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 148, Col: 32} | ||||||
| 		} | 		} | ||||||
| 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34)) | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34)) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\" id=\"") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" id=\"") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		var templ_7745c5c3_Var35 string | 		var templ_7745c5c3_Var35 string | ||||||
| 		templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(id) | 		templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(id) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 155, Col: 42} | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 148, Col: 42} | ||||||
| 		} | 		} | ||||||
| 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35)) | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35)) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "\" value=\"") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\" value=\"") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		var templ_7745c5c3_Var36 string | 		var templ_7745c5c3_Var36 string | ||||||
| 		templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(value) | 		templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(value) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 155, Col: 58} | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 148, Col: 58} | ||||||
| 		} | 		} | ||||||
| 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "\"") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "\"") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		if selected { | 		if selected { | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, " selected") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, " selected") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, ">") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, ">") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| @ -784,7 +746,7 @@ func GuestbookSettingsView(data CommonData, website models.Website) templ.Compon | |||||||
| 				}() | 				}() | ||||||
| 			} | 			} | ||||||
| 			ctx = templ.InitializeContext(ctx) | 			ctx = templ.InitializeContext(ctx) | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "<div id=\"dashboard\">") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "<div id=\"dashboard\">") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| @ -792,143 +754,143 @@ func GuestbookSettingsView(data CommonData, website models.Website) templ.Compon | |||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "<div><h1>Guestbook Settings</h1><form hx-put=\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "<div><h1>Guestbook Settings</h1><form hx-put=\"") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			var templ_7745c5c3_Var39 string | 			var templ_7745c5c3_Var39 string | ||||||
| 			templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(putUrl) | 			templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(putUrl) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 166, Col: 25} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 159, Col: 25} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "\"><input type=\"hidden\" name=\"csrf_token\" value=\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "\"><input type=\"hidden\" name=\"csrf_token\" value=\"") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			var templ_7745c5c3_Var40 string | 			var templ_7745c5c3_Var40 string | ||||||
| 			templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(data.CSRFToken) | 			templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(data.CSRFToken) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 167, Col: 66} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 160, Col: 66} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "\"><div><label>Guestbook Visibility</label> <label for=\"gb_visible_true\"><input type=\"radio\" name=\"gb_visible\" id=\"gb_visible_true\" value=\"true\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "\"><div><label>Guestbook Visibility</label> <label for=\"gb_visible_true\"><input type=\"radio\" name=\"gb_visible\" id=\"gb_visible_true\" value=\"true\"") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			if gb.Settings.IsVisible { | 			if gb.Settings.IsVisible { | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, " checked") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, " checked") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "> Public</label> <label for=\"gb_visible_false\"><input type=\"radio\" name=\"gb_visible\" id=\"gb_visible_false\" value=\"false\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "> Public</label> <label for=\"gb_visible_false\"><input type=\"radio\" name=\"gb_visible\" id=\"gb_visible_false\" value=\"false\"") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			if !gb.Settings.IsVisible { | 			if !gb.Settings.IsVisible { | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, " checked") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, " checked") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "> Private</label></div><div><label>Guestbook Commenting</label> <select name=\"gb_commenting\" id=\"gb-commenting\"><option value=\"true\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "> Private</label></div><div><label>Guestbook Commenting</label> <select name=\"gb_commenting\" id=\"gb-commenting\"><option value=\"true\"") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			if gb.Settings.IsCommentingEnabled { | 			if gb.Settings.IsCommentingEnabled { | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, " selected") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, " selected") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, ">Enabled</option> <option value=\"1h\">Disabled for 1 Hour</option> <option value=\"4h\">Disabled for 4 Hours</option> <option value=\"8h\">Disabled for 8 Hours</option> <option value=\"24h\">Disabled for 1 Day</option> <option value=\"72h\">Disabled for 3 Days</option> <option value=\"168h\">Disabled for 7 Days</option> <option value=\"false\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, ">Enabled</option> <option value=\"1h\">Disabled for 1 Hour</option> <option value=\"4h\">Disabled for 4 Hours</option> <option value=\"8h\">Disabled for 8 Hours</option> <option value=\"24h\">Disabled for 1 Day</option> <option value=\"72h\">Disabled for 3 Days</option> <option value=\"168h\">Disabled for 7 Days</option> <option value=\"false\"") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			if !gb.Settings.IsCommentingEnabled { | 			if !gb.Settings.IsCommentingEnabled { | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, " selected") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, " selected") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, ">Disabled</option></select> ") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, ">Disabled</option></select> ") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			if !website.Guestbook.CanComment() { | 			if !website.Guestbook.CanComment() { | ||||||
| 				localtime := gb.Settings.ReenableCommenting.In(data.CurrentUser.Settings.LocalTimezone) | 				localtime := gb.Settings.ReenableCommenting.In(data.CurrentUser.Settings.LocalTimezone) | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "<label>Commenting re-enabled on <time value=\"") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "<label>Commenting re-enabled on <time value=\"") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				var templ_7745c5c3_Var41 string | 				var templ_7745c5c3_Var41 string | ||||||
| 				templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(localtime.Format(time.RFC3339)) | 				templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(localtime.Format(time.RFC3339)) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 193, Col: 83} | 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 186, Col: 83} | ||||||
| 				} | 				} | ||||||
| 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41)) | 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41)) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "\">") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "\">") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				var templ_7745c5c3_Var42 string | 				var templ_7745c5c3_Var42 string | ||||||
| 				templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(localtime.Format("2 January 2006")) | 				templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(localtime.Format("2 January 2006")) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 193, Col: 122} | 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 186, Col: 122} | ||||||
| 				} | 				} | ||||||
| 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42)) | 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42)) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, " at ") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, " at ") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				var templ_7745c5c3_Var43 string | 				var templ_7745c5c3_Var43 string | ||||||
| 				templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(localtime.Format("3:04PM MST")) | 				templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(localtime.Format("3:04PM MST")) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 193, Col: 160} | 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 186, Col: 160} | ||||||
| 				} | 				} | ||||||
| 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43)) | 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43)) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "</time></label>") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "</time></label>") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "</div><div><label>Enable Widgets</label> <label for=\"gb_remote_true\"><input type=\"radio\" name=\"gb_remote\" id=\"gb_remote_true\" value=\"true\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "</div><div><label>Enable Widgets</label> <label for=\"gb_remote_true\"><input type=\"radio\" name=\"gb_remote\" id=\"gb_remote_true\" value=\"true\"") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			if gb.Settings.AllowRemoteHostAccess { | 			if gb.Settings.AllowRemoteHostAccess { | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, " checked") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, " checked") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "> Yes</label> <label for=\"gb_remote_false\"><input type=\"radio\" name=\"gb_remote\" id=\"gb_remote_false\" value=\"false\"") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "> Yes</label> <label for=\"gb_remote_false\"><input type=\"radio\" name=\"gb_remote\" id=\"gb_remote_false\" value=\"false\"") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			if !gb.Settings.AllowRemoteHostAccess { | 			if !gb.Settings.AllowRemoteHostAccess { | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, " checked") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, " checked") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "> No</label></div><input type=\"submit\" value=\"Submit\"></form></div></div>") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "> No</label></div><input type=\"submit\" value=\"Submit\"></form></div></div>") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| @ -942,6 +904,79 @@ func GuestbookSettingsView(data CommonData, website models.Website) templ.Compon | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func EmbeddableGuestbookCommentForm(data CommonData, w models.Website, f forms.CommentCreateForm) 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_Var44 := templ.GetChildren(ctx) | ||||||
|  | 		if templ_7745c5c3_Var44 == nil { | ||||||
|  | 			templ_7745c5c3_Var44 = templ.NopComponent | ||||||
|  | 		} | ||||||
|  | 		ctx = templ.ClearChildren(ctx) | ||||||
|  | 		postUrl := fmt.Sprintf("/websites/%s/guestbook/comments/create?headless=true", shortIdToSlug(w.ShortId)) | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "<html><head><link href=\"/static/css/classless.min.css\" rel=\"stylesheet\"></head><body>") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var45 string | ||||||
|  | 		templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(data.Flash) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 214, Col: 15} | ||||||
|  | 		} | ||||||
|  | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45)) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "<form action=\"") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var46 templ.SafeURL = templ.URL(postUrl) | ||||||
|  | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var46))) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "\" method=\"post\"><input type=\"hidden\" name=\"csrf_token\" value=\"") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var47 string | ||||||
|  | 		templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(data.CSRFToken) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 216, Col: 65} | ||||||
|  | 		} | ||||||
|  | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47)) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "\">") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = commentForm(f).Render(ctx, templ_7745c5c3_Buffer) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "</form></body></html>") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func AllGuestbooksView(data CommonData, websites []models.Website) templ.Component { | func AllGuestbooksView(data CommonData, websites []models.Website) templ.Component { | ||||||
| 	return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 	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 | 		templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||||||
| @ -958,12 +993,12 @@ func AllGuestbooksView(data CommonData, websites []models.Website) templ.Compone | |||||||
| 			}() | 			}() | ||||||
| 		} | 		} | ||||||
| 		ctx = templ.InitializeContext(ctx) | 		ctx = templ.InitializeContext(ctx) | ||||||
| 		templ_7745c5c3_Var44 := templ.GetChildren(ctx) | 		templ_7745c5c3_Var48 := templ.GetChildren(ctx) | ||||||
| 		if templ_7745c5c3_Var44 == nil { | 		if templ_7745c5c3_Var48 == nil { | ||||||
| 			templ_7745c5c3_Var44 = templ.NopComponent | 			templ_7745c5c3_Var48 = templ.NopComponent | ||||||
| 		} | 		} | ||||||
| 		ctx = templ.ClearChildren(ctx) | 		ctx = templ.ClearChildren(ctx) | ||||||
| 		templ_7745c5c3_Var45 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 		templ_7745c5c3_Var49 := 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_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||||||
| 			templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | 			templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | ||||||
| 			if !templ_7745c5c3_IsBuffer { | 			if !templ_7745c5c3_IsBuffer { | ||||||
| @ -975,50 +1010,165 @@ func AllGuestbooksView(data CommonData, websites []models.Website) templ.Compone | |||||||
| 				}() | 				}() | ||||||
| 			} | 			} | ||||||
| 			ctx = templ.InitializeContext(ctx) | 			ctx = templ.InitializeContext(ctx) | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "<div><h1>All Guestbooks</h1><p>This page exists only for testing the service.</p><ul>") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "<div><h1>All Guestbooks</h1><p>This page exists only for testing the service.</p><ul>") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			for _, w := range websites { | 			for _, w := range websites { | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "<li>") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "<li>") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				gbUrl := fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(w.ShortId)) | 				gbUrl := fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(w.ShortId)) | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "<a href=\"") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "<a href=\"") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				var templ_7745c5c3_Var46 templ.SafeURL = templ.URL(gbUrl) | 				var templ_7745c5c3_Var50 templ.SafeURL = templ.URL(gbUrl) | ||||||
| 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var46))) | 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var50))) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "\" target=\"_blank\">") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "\" target=\"_blank\">") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				var templ_7745c5c3_Var47 string | 				var templ_7745c5c3_Var51 string | ||||||
| 				templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(w.Name) | 				templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(w.Name) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 225, Col: 59} | 					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 234, Col: 59} | ||||||
| 				} | 				} | ||||||
| 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47)) | 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51)) | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "</a></li>") | 				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "</a></li>") | ||||||
| 				if templ_7745c5c3_Err != nil { | 				if templ_7745c5c3_Err != nil { | ||||||
| 					return templ_7745c5c3_Err | 					return templ_7745c5c3_Err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "</ul></div>") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "</ul></div>") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			return nil | 			return nil | ||||||
| 		}) | 		}) | ||||||
| 		templ_7745c5c3_Err = base("All Guestbooks", data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var45), templ_7745c5c3_Buffer) | 		templ_7745c5c3_Err = base("All Guestbooks", data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var49), templ_7745c5c3_Buffer) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func GuestbookCommentCreateRemoteErrorView(url, err 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_Var52 := templ.GetChildren(ctx) | ||||||
|  | 		if templ_7745c5c3_Var52 == nil { | ||||||
|  | 			templ_7745c5c3_Var52 = templ.NopComponent | ||||||
|  | 		} | ||||||
|  | 		ctx = templ.ClearChildren(ctx) | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "<html><head><meta http-equiv=\"refresh\" content=\"") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var53 string | ||||||
|  | 		templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("3; url='%s'", templ.URL(externalUrl(url)))) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 245, Col: 95} | ||||||
|  | 		} | ||||||
|  | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var53)) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "\"></head><body><p>An error occurred while posting comment. ") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var54 string | ||||||
|  | 		templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(err) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 249, Col: 50} | ||||||
|  | 		} | ||||||
|  | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54)) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, ". Redirecting.</p><p><a href=\"") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var55 templ.SafeURL = templ.URL(url) | ||||||
|  | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var55))) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, "\">Redirect</a></p></body></html>") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func GuestbookCommentCreateRemoteSuccessView(url 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_Var56 := templ.GetChildren(ctx) | ||||||
|  | 		if templ_7745c5c3_Var56 == nil { | ||||||
|  | 			templ_7745c5c3_Var56 = templ.NopComponent | ||||||
|  | 		} | ||||||
|  | 		ctx = templ.ClearChildren(ctx) | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "<html><head><meta http-equiv=\"refresh\" content=\"") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var57 string | ||||||
|  | 		templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("3; url='%s'", templ.URL(externalUrl(url)))) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 261, Col: 95} | ||||||
|  | 		} | ||||||
|  | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57)) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, "\"></head><body><p>Comment successfully posted. Redirecting.</p><p><a href=\"") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var58 templ.SafeURL = templ.URL(url) | ||||||
|  | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var58))) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, "\">Redirect</a></p></body></html>") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -1,19 +1,19 @@ | |||||||
| package views | package views | ||||||
| 
 | 
 | ||||||
| templ Home(title string, data CommonData) { | templ Home(title string, data CommonData) { | ||||||
|     @base(title, data) { | 	@base(title, data) { | ||||||
|         <h2>Welcome</h2> | 		<h2>Welcome</h2> | ||||||
|         <p> | 		<p> | ||||||
|             Welcome to webweav.ing, a collection of webmastery tools created by the <a href="https://32bit.cafe">32-Bit Cafe</a>. | 			Welcome to webweav.ing, a collection of webmastery tools created by the <a href="https://32bit.cafe">32-Bit Cafe</a>. | ||||||
|         </p> | 		</p> | ||||||
|         <p> | 		<p> | ||||||
|             Note this service is in a pre-alpha state. Your account and data can disappear at any time.  | 			Note this service is in a pre-alpha state. Your account and data can disappear at any time.  | ||||||
|         </p> | 		</p> | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| templ ComingSoon(title string, data CommonData) { | templ ComingSoon(title string, data CommonData) { | ||||||
|     @base(title, data) { | 	@base(title, data) { | ||||||
|         <h2>Coming Soon</h2> | 		<h2>Coming Soon</h2> | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| @ -16,7 +16,7 @@ templ wSidebar(website models.Website) { | |||||||
| 			<h2>{ website.Name }</h2> | 			<h2>{ website.Name }</h2> | ||||||
| 			<ul> | 			<ul> | ||||||
| 				<li><a href={ templ.URL(dashUrl) }>Dashboard</a></li> | 				<li><a href={ templ.URL(dashUrl) }>Dashboard</a></li> | ||||||
| 				<li><a href={ templ.URL(externalUrl(website.SiteUrl)) } target="_blank">View Website</a></li> | 				<li><a href={ templ.URL(externalUrl(website.Url.String())) } target="_blank">View Website</a></li> | ||||||
| 			</ul> | 			</ul> | ||||||
| 			<h3>Guestbook</h3> | 			<h3>Guestbook</h3> | ||||||
| 			<ul> | 			<ul> | ||||||
| @ -70,7 +70,7 @@ templ websiteCreateForm(csrfToken string, form forms.WebsiteCreateForm) { | |||||||
| 		if exists { | 		if exists { | ||||||
| 			<label class="error">{ err }</label> | 			<label class="error">{ err }</label> | ||||||
| 		} | 		} | ||||||
| 		<input type="text" name="sitename" id="sitename" required/> | 		<input type="text" name="sitename" id="sitename" value={ form.Name } required/> | ||||||
| 	</div> | 	</div> | ||||||
| 	<div> | 	<div> | ||||||
| 		{{ err, exists = form.FieldErrors["siteurl"] }} | 		{{ err, exists = form.FieldErrors["siteurl"] }} | ||||||
| @ -78,7 +78,7 @@ templ websiteCreateForm(csrfToken string, form forms.WebsiteCreateForm) { | |||||||
| 		if exists { | 		if exists { | ||||||
| 			<label class="error">{ err }</label> | 			<label class="error">{ err }</label> | ||||||
| 		} | 		} | ||||||
| 		<input type="text" name="siteurl" id="siteurl" required/> | 		<input type="text" name="siteurl" id="siteurl" value={ form.SiteUrl } required/> | ||||||
| 	</div> | 	</div> | ||||||
| 	<div> | 	<div> | ||||||
| 		{{ err, exists = form.FieldErrors["authorname"] }} | 		{{ err, exists = form.FieldErrors["authorname"] }} | ||||||
| @ -86,22 +86,18 @@ templ websiteCreateForm(csrfToken string, form forms.WebsiteCreateForm) { | |||||||
| 		if exists { | 		if exists { | ||||||
| 			<label class="error">{ err }</label> | 			<label class="error">{ err }</label> | ||||||
| 		} | 		} | ||||||
| 		<input type="text" name="authorname" id="authorname" required/> | 		<input type="text" name="authorname" id="authorname" value={ form.AuthorName } required/> | ||||||
| 	</div> | 	</div> | ||||||
| 	<div> | 	<div> | ||||||
| 		<button type="submit">Submit</button> | 		<button type="submit">Submit</button> | ||||||
| 	</div> | 	</div> | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| templ WebsiteCreateButton() { |  | ||||||
| 	<button hx-get="/websites/create" hx-target="closest div">Add Website</button> |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| templ WebsiteList(title string, data CommonData, websites []models.Website) { | templ WebsiteList(title string, data CommonData, websites []models.Website) { | ||||||
| 	@base(title, data) { | 	@base(title, data) { | ||||||
| 		<h1>My Websites</h1> | 		<h1>My Websites</h1> | ||||||
| 		<div> | 		<div> | ||||||
| 			@WebsiteCreateButton() | 			<a href="/websites/create">Add Website</a> | ||||||
| 		</div> | 		</div> | ||||||
| 		<div> | 		<div> | ||||||
| 			@displayWebsites(websites) | 			@displayWebsites(websites) | ||||||
| @ -115,9 +111,42 @@ templ WebsiteDashboard(title string, data CommonData, website models.Website) { | |||||||
| 			@wSidebar(website) | 			@wSidebar(website) | ||||||
| 			<div> | 			<div> | ||||||
| 				<h1>{ website.Name }</h1> | 				<h1>{ website.Name }</h1> | ||||||
|  | 				<h2>Embed your Guestbook</h2> | ||||||
| 				<p> | 				<p> | ||||||
| 					Stats and stuff will go here. | 					Upload <a href="/static/js/guestbook.js" download>this JavaScript WebComponent</a> to your site and include it in your <code>{ `<head>` }</code> tag. | ||||||
| 				</p> | 				</p> | ||||||
|  | 				<div> | ||||||
|  | 					//<button>Copy to Clipboard</button> | ||||||
|  | 					<pre> | ||||||
|  | 						<code id="guestbookSnippet"> | ||||||
|  | 							{  | ||||||
|  | `<head> | ||||||
|  |     <script type="module" src="js/guestbook.js"></script> | ||||||
|  | </head>` } | ||||||
|  | 						</code> | ||||||
|  | 					</pre> | ||||||
|  | 					<p> | ||||||
|  | 						Then add the custom elements where you want your form and comments to show up | ||||||
|  | 					</p> | ||||||
|  | 					{{ gbUrl := fmt.Sprintf("https://%s/websites/%s/guestbook", data.RootUrl, shortIdToSlug(website.ShortId)) }} | ||||||
|  | 					//<button>Copy to Clipboard</button> | ||||||
|  | 					<pre> | ||||||
|  | 						<code> | ||||||
|  | 							{ fmt.Sprintf(`<guestbook-form guestbook="%s"></guestbook-form> | ||||||
|  | <guestbook-comments guestbook="%s"></guestbook-comments>`, gbUrl, gbUrl) } | ||||||
|  | 						</code> | ||||||
|  | 					</pre> | ||||||
|  | 				</div> | ||||||
|  | 				<p> | ||||||
|  | 					If your web host does not allow CORS requests, use an iframe instead | ||||||
|  | 				</p> | ||||||
|  | 				<div> | ||||||
|  | 					<pre> | ||||||
|  | 						<code> | ||||||
|  | 							{ fmt.Sprintf(`<iframe src="%s" title="Guestbook"></iframe>`, gbUrl) } | ||||||
|  | 						</code> | ||||||
|  | 					</pre> | ||||||
|  | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 	} | 	} | ||||||
| @ -138,7 +167,9 @@ templ WebsiteDashboardComingSoon(title string, data CommonData, website models.W | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| templ WebsiteCreate(title string, data CommonData, form forms.WebsiteCreateForm) { | templ WebsiteCreate(title string, data CommonData, form forms.WebsiteCreateForm) { | ||||||
| 	<form hx-post="/websites/create" hx-target="closest div"> | 	@base(title, data) { | ||||||
| 		@websiteCreateForm(data.CSRFToken, form) | 		<form action="/websites/create" method="post"> | ||||||
| 	</form> | 			@websiteCreateForm(data.CSRFToken, form) | ||||||
|  | 		</form> | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -65,7 +65,7 @@ func wSidebar(website models.Website) templ.Component { | |||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		var templ_7745c5c3_Var4 templ.SafeURL = templ.URL(externalUrl(website.SiteUrl)) | 		var templ_7745c5c3_Var4 templ.SafeURL = templ.URL(externalUrl(website.Url.String())) | ||||||
| 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4))) | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4))) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| @ -271,92 +271,102 @@ func websiteCreateForm(csrfToken string, form forms.WebsiteCreateForm) templ.Com | |||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<input type=\"text\" name=\"sitename\" id=\"sitename\" required></div><div>") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<input type=\"text\" name=\"sitename\" id=\"sitename\" value=\"") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var18 string | ||||||
|  | 		templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(form.Name) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 73, Col: 68} | ||||||
|  | 		} | ||||||
|  | 		_, 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, 24, "\" required></div><div>") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		err, exists = form.FieldErrors["siteurl"] | 		err, exists = form.FieldErrors["siteurl"] | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<label for=\"siteurl\">Site URL: </label> ") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<label for=\"siteurl\">Site URL: </label> ") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		if exists { | 		if exists { | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<label class=\"error\">") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<label class=\"error\">") | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			var templ_7745c5c3_Var18 string |  | ||||||
| 			templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(err) |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 79, Col: 29} |  | ||||||
| 			} |  | ||||||
| 			_, 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, 26, "</label> ") |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "<input type=\"text\" name=\"siteurl\" id=\"siteurl\" required></div><div>") |  | ||||||
| 		if templ_7745c5c3_Err != nil { |  | ||||||
| 			return templ_7745c5c3_Err |  | ||||||
| 		} |  | ||||||
| 		err, exists = form.FieldErrors["authorname"] |  | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<label for=\"authorname\">Site Author: </label> ") |  | ||||||
| 		if templ_7745c5c3_Err != nil { |  | ||||||
| 			return templ_7745c5c3_Err |  | ||||||
| 		} |  | ||||||
| 		if exists { |  | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<label class=\"error\">") |  | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			var templ_7745c5c3_Var19 string | 			var templ_7745c5c3_Var19 string | ||||||
| 			templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(err) | 			templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(err) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 87, Col: 29} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 79, Col: 29} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</label> ") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</label> ") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<input type=\"text\" name=\"authorname\" id=\"authorname\" required></div><div><button type=\"submit\">Submit</button></div>") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<input type=\"text\" name=\"siteurl\" id=\"siteurl\" value=\"") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| 		return nil | 		var templ_7745c5c3_Var20 string | ||||||
| 	}) | 		templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(form.SiteUrl) | ||||||
| } | 		if templ_7745c5c3_Err != nil { | ||||||
| 
 | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 81, Col: 69} | ||||||
| func WebsiteCreateButton() 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) | 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) | ||||||
| 		if !templ_7745c5c3_IsBuffer { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			defer func() { | 			return templ_7745c5c3_Err | ||||||
| 				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, "\" required></div><div>") | ||||||
| 		templ_7745c5c3_Var20 := templ.GetChildren(ctx) | 		if templ_7745c5c3_Err != nil { | ||||||
| 		if templ_7745c5c3_Var20 == nil { | 			return templ_7745c5c3_Err | ||||||
| 			templ_7745c5c3_Var20 = templ.NopComponent |  | ||||||
| 		} | 		} | ||||||
| 		ctx = templ.ClearChildren(ctx) | 		err, exists = form.FieldErrors["authorname"] | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<button hx-get=\"/websites/create\" hx-target=\"closest div\">Add Website</button>") | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<label for=\"authorname\">Site Author: </label> ") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		if exists { | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<label class=\"error\">") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			var templ_7745c5c3_Var21 string | ||||||
|  | 			templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(err) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 87, Col: 29} | ||||||
|  | 			} | ||||||
|  | 			_, 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, 32, "</label> ") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "<input type=\"text\" name=\"authorname\" id=\"authorname\" value=\"") | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		var templ_7745c5c3_Var22 string | ||||||
|  | 		templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(form.AuthorName) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 89, Col: 78} | ||||||
|  | 		} | ||||||
|  | 		_, 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, 34, "\" required></div><div><button type=\"submit\">Submit</button></div>") | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| @ -365,69 +375,6 @@ func WebsiteCreateButton() templ.Component { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func WebsiteList(title string, data CommonData, websites []models.Website) templ.Component { | func WebsiteList(title string, data CommonData, websites []models.Website) 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_Var21 := templ.GetChildren(ctx) |  | ||||||
| 		if templ_7745c5c3_Var21 == nil { |  | ||||||
| 			templ_7745c5c3_Var21 = templ.NopComponent |  | ||||||
| 		} |  | ||||||
| 		ctx = templ.ClearChildren(ctx) |  | ||||||
| 		templ_7745c5c3_Var22 := 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, 33, "<h1>My Websites</h1><div>") |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			templ_7745c5c3_Err = WebsiteCreateButton().Render(ctx, templ_7745c5c3_Buffer) |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</div><div>") |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			templ_7745c5c3_Err = displayWebsites(websites).Render(ctx, templ_7745c5c3_Buffer) |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</div>") |  | ||||||
| 			if templ_7745c5c3_Err != nil { |  | ||||||
| 				return templ_7745c5c3_Err |  | ||||||
| 			} |  | ||||||
| 			return nil |  | ||||||
| 		}) |  | ||||||
| 		templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var22), templ_7745c5c3_Buffer) |  | ||||||
| 		if templ_7745c5c3_Err != nil { |  | ||||||
| 			return templ_7745c5c3_Err |  | ||||||
| 		} |  | ||||||
| 		return nil |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func WebsiteDashboard(title string, data CommonData, website models.Website) templ.Component { |  | ||||||
| 	return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 	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 | 		templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||||||
| 		if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { | 		if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { | ||||||
| @ -460,7 +407,62 @@ func WebsiteDashboard(title string, data CommonData, website models.Website) tem | |||||||
| 				}() | 				}() | ||||||
| 			} | 			} | ||||||
| 			ctx = templ.InitializeContext(ctx) | 			ctx = templ.InitializeContext(ctx) | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "<div id=\"dashboard\">") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<h1>My Websites</h1><div><a href=\"/websites/create\">Add Website</a></div><div>") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			templ_7745c5c3_Err = displayWebsites(websites).Render(ctx, templ_7745c5c3_Buffer) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</div>") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			return nil | ||||||
|  | 		}) | ||||||
|  | 		templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var24), templ_7745c5c3_Buffer) | ||||||
|  | 		if templ_7745c5c3_Err != nil { | ||||||
|  | 			return templ_7745c5c3_Err | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func WebsiteDashboard(title string, data CommonData, website models.Website) 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_Var25 := templ.GetChildren(ctx) | ||||||
|  | 		if templ_7745c5c3_Var25 == nil { | ||||||
|  | 			templ_7745c5c3_Var25 = templ.NopComponent | ||||||
|  | 		} | ||||||
|  | 		ctx = templ.ClearChildren(ctx) | ||||||
|  | 		templ_7745c5c3_Var26 := 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, 37, "<div id=\"dashboard\">") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| @ -468,26 +470,87 @@ func WebsiteDashboard(title string, data CommonData, website models.Website) tem | |||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<div><h1>") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "<div><h1>") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			var templ_7745c5c3_Var25 string | 			var templ_7745c5c3_Var27 string | ||||||
| 			templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name) | 			templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 117, Col: 22} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 113, Col: 22} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</h1><p>Stats and stuff will go here.</p></div></div>") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</h1><h2>Embed your Guestbook</h2><p>Upload <a href=\"/static/js/guestbook.js\" download>this JavaScript WebComponent</a> to your site and include it in your <code>") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			var templ_7745c5c3_Var28 string | ||||||
|  | 			templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(`<head>`) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 116, Col: 140} | ||||||
|  | 			} | ||||||
|  | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</code> tag.</p><div><pre><code id=\"guestbookSnippet\">") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			var templ_7745c5c3_Var29 string | ||||||
|  | 			templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs( | ||||||
|  | 				`<head> | ||||||
|  |     <script type="module" src="js/guestbook.js"></script> | ||||||
|  | </head>`) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 125, Col: 8} | ||||||
|  | 			} | ||||||
|  | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "</code></pre><p>Then add the custom elements where you want your form and comments to show up</p>") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			gbUrl := fmt.Sprintf("https://%s/websites/%s/guestbook", data.RootUrl, shortIdToSlug(website.ShortId)) | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<pre><code>") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			var templ_7745c5c3_Var30 string | ||||||
|  | 			templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(`<guestbook-form guestbook="%s"></guestbook-form> | ||||||
|  | <guestbook-comments guestbook="%s"></guestbook-comments>`, gbUrl, gbUrl)) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 136, Col: 72} | ||||||
|  | 			} | ||||||
|  | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "</code></pre></div><p>If your web host does not allow CORS requests, use an iframe instead</p><div><pre><code>") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			var templ_7745c5c3_Var31 string | ||||||
|  | 			templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(`<iframe src="%s" title="Guestbook"></iframe>`, gbUrl)) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 146, Col: 75} | ||||||
|  | 			} | ||||||
|  | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "</code></pre></div></div></div>") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			return nil | 			return nil | ||||||
| 		}) | 		}) | ||||||
| 		templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var24), templ_7745c5c3_Buffer) | 		templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var26), templ_7745c5c3_Buffer) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| @ -511,12 +574,12 @@ func WebsiteDashboardComingSoon(title string, data CommonData, website models.We | |||||||
| 			}() | 			}() | ||||||
| 		} | 		} | ||||||
| 		ctx = templ.InitializeContext(ctx) | 		ctx = templ.InitializeContext(ctx) | ||||||
| 		templ_7745c5c3_Var26 := templ.GetChildren(ctx) | 		templ_7745c5c3_Var32 := templ.GetChildren(ctx) | ||||||
| 		if templ_7745c5c3_Var26 == nil { | 		if templ_7745c5c3_Var32 == nil { | ||||||
| 			templ_7745c5c3_Var26 = templ.NopComponent | 			templ_7745c5c3_Var32 = templ.NopComponent | ||||||
| 		} | 		} | ||||||
| 		ctx = templ.ClearChildren(ctx) | 		ctx = templ.ClearChildren(ctx) | ||||||
| 		templ_7745c5c3_Var27 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 		templ_7745c5c3_Var33 := 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_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||||||
| 			templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | 			templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | ||||||
| 			if !templ_7745c5c3_IsBuffer { | 			if !templ_7745c5c3_IsBuffer { | ||||||
| @ -528,7 +591,7 @@ func WebsiteDashboardComingSoon(title string, data CommonData, website models.We | |||||||
| 				}() | 				}() | ||||||
| 			} | 			} | ||||||
| 			ctx = templ.InitializeContext(ctx) | 			ctx = templ.InitializeContext(ctx) | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<div id=\"dashboard\">") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "<div id=\"dashboard\">") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| @ -536,26 +599,26 @@ func WebsiteDashboardComingSoon(title string, data CommonData, website models.We | |||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "<div><h1>") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "<div><h1>") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			var templ_7745c5c3_Var28 string | 			var templ_7745c5c3_Var34 string | ||||||
| 			templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name) | 			templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 131, Col: 22} | 				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 160, Col: 22} | ||||||
| 			} | 			} | ||||||
| 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) | 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34)) | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "</h1><p>Coming Soon</p></div></div>") | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "</h1><p>Coming Soon</p></div></div>") | ||||||
| 			if templ_7745c5c3_Err != nil { | 			if templ_7745c5c3_Err != nil { | ||||||
| 				return templ_7745c5c3_Err | 				return templ_7745c5c3_Err | ||||||
| 			} | 			} | ||||||
| 			return nil | 			return nil | ||||||
| 		}) | 		}) | ||||||
| 		templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var27), templ_7745c5c3_Buffer) | 		templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var33), templ_7745c5c3_Buffer) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
| @ -579,20 +642,38 @@ func WebsiteCreate(title string, data CommonData, form forms.WebsiteCreateForm) | |||||||
| 			}() | 			}() | ||||||
| 		} | 		} | ||||||
| 		ctx = templ.InitializeContext(ctx) | 		ctx = templ.InitializeContext(ctx) | ||||||
| 		templ_7745c5c3_Var29 := templ.GetChildren(ctx) | 		templ_7745c5c3_Var35 := templ.GetChildren(ctx) | ||||||
| 		if templ_7745c5c3_Var29 == nil { | 		if templ_7745c5c3_Var35 == nil { | ||||||
| 			templ_7745c5c3_Var29 = templ.NopComponent | 			templ_7745c5c3_Var35 = templ.NopComponent | ||||||
| 		} | 		} | ||||||
| 		ctx = templ.ClearChildren(ctx) | 		ctx = templ.ClearChildren(ctx) | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<form hx-post=\"/websites/create\" hx-target=\"closest div\">") | 		templ_7745c5c3_Var36 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | ||||||
| 		if templ_7745c5c3_Err != nil { | 			templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||||||
| 			return templ_7745c5c3_Err | 			templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | ||||||
| 		} | 			if !templ_7745c5c3_IsBuffer { | ||||||
| 		templ_7745c5c3_Err = websiteCreateForm(data.CSRFToken, form).Render(ctx, templ_7745c5c3_Buffer) | 				defer func() { | ||||||
| 		if templ_7745c5c3_Err != nil { | 					templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) | ||||||
| 			return templ_7745c5c3_Err | 					if templ_7745c5c3_Err == nil { | ||||||
| 		} | 						templ_7745c5c3_Err = templ_7745c5c3_BufErr | ||||||
| 		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "</form>") | 					} | ||||||
|  | 				}() | ||||||
|  | 			} | ||||||
|  | 			ctx = templ.InitializeContext(ctx) | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "<form action=\"/websites/create\" method=\"post\">") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			templ_7745c5c3_Err = websiteCreateForm(data.CSRFToken, form).Render(ctx, templ_7745c5c3_Buffer) | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</form>") | ||||||
|  | 			if templ_7745c5c3_Err != nil { | ||||||
|  | 				return templ_7745c5c3_Err | ||||||
|  | 			} | ||||||
|  | 			return nil | ||||||
|  | 		}) | ||||||
|  | 		templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var36), templ_7745c5c3_Buffer) | ||||||
| 		if templ_7745c5c3_Err != nil { | 		if templ_7745c5c3_Err != nil { | ||||||
| 			return templ_7745c5c3_Err | 			return templ_7745c5c3_Err | ||||||
| 		} | 		} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user