272 lines
8.7 KiB
Plaintext
272 lines
8.7 KiB
Plaintext
package views
|
|
|
|
import "fmt"
|
|
import "git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
|
import "git.32bit.cafe/32bitcafe/guestbook/internal/forms"
|
|
import "time"
|
|
|
|
templ GuestbookDashboardCommentsView(title string, data CommonData, website models.Website, guestbook models.Guestbook, comments []models.GuestbookComment) {
|
|
@base(title, data) {
|
|
<div id="dashboard">
|
|
@wSidebar(website)
|
|
<div>
|
|
<section aria-labelledby="comments-management-heading">
|
|
<header class="section-header">
|
|
<h1 id="comments-management-heading">Comments on { website.Name }</h1>
|
|
<p class="section-description">Manage, moderate, and organize comments on your guestbook</p>
|
|
</header>
|
|
<hr role="separator"/>
|
|
if len(comments) == 0 {
|
|
<p>No comments yet!</p>
|
|
}
|
|
for i, c := range comments {
|
|
@GuestbookDashboardCommentView(data, website, c, i)
|
|
}
|
|
</section>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
|
|
templ GuestbookDashboardCommentDeletePart(text string) {
|
|
<div class="comment-update-msg">
|
|
<p>{ text }</p>
|
|
</div>
|
|
}
|
|
|
|
templ GuestbookDashboardUpdateButtonPart(data CommonData, w models.Website, c models.GuestbookComment) {
|
|
{{ hxHeaders := fmt.Sprintf("{\"X-CSRF-Token\": \"%s\"}", data.CSRFToken) }}
|
|
{{ commentUrl := fmt.Sprintf("%s/dashboard/guestbook/comments/%s", wUrl(w), shortIdToSlug(c.ShortId)) }}
|
|
<button
|
|
type="button"
|
|
class="outline"
|
|
hx-put={ commentUrl }
|
|
hx-headers={ hxHeaders }
|
|
hx-swap="outerHTML"
|
|
>
|
|
if !c.IsPublished {
|
|
Publish
|
|
} else {
|
|
Hide
|
|
}
|
|
</button>
|
|
}
|
|
|
|
templ GuestbookDashboardCommentView(data CommonData, w models.Website, c models.GuestbookComment, i int) {
|
|
{{ commentUrl := fmt.Sprintf("%s/dashboard/guestbook/comments/%s", wUrl(w), shortIdToSlug(c.ShortId)) }}
|
|
{{ hxHeaders := fmt.Sprintf("{\"X-CSRF-Token\": \"%s\"}", data.CSRFToken) }}
|
|
{{ authorClass := fmt.Sprintf("comment-author-%d", i) }}
|
|
<article class="comment" role="article" aria-labelledby={ authorClass }>
|
|
<div class="comment-update-msg"></div>
|
|
<header class="comment-header">
|
|
<div class="comment-meta">
|
|
<h3 id={ authorClass } class="comment-author">{ c.AuthorName }</h3>
|
|
<time datetime={ c.Created.In(data.CurrentUser.Settings.LocalTimezone).Format("01-02-2006 03:04PM") }>{ c.Created.In(data.CurrentUser.Settings.LocalTimezone).Format("01-02-2006 03:04PM") }</time>
|
|
if len(c.AuthorEmail) > 0 {
|
|
<div class="comment-contact">
|
|
{{ email := "mailto:" + c.AuthorEmail }}
|
|
<i class="fa-solid fa-envelope"></i>
|
|
<a href={ templ.URL(email) } target="_blank">{ c.AuthorEmail }</a>
|
|
</div>
|
|
}
|
|
if len(c.AuthorSite) > 0 {
|
|
<div class="comment-contact">
|
|
<i class="fa-solid fa-house"></i>
|
|
<a href={ templ.URL(externalUrl(c.AuthorSite)) } target="_blank">{ c.AuthorSite }</a>
|
|
</div>
|
|
}
|
|
</div>
|
|
<div class="comment-actions" role="group" aria-label={ fmt.Sprintf("Actions for comment by %s", c.AuthorName) }>
|
|
if c.Deleted.IsZero() {
|
|
<button
|
|
type="button"
|
|
class="danger"
|
|
hx-delete={ commentUrl }
|
|
hx-target="closest article.comment"
|
|
hx-confirm="Are you sure you want to delete this comment? This action cannot be undone."
|
|
hx-headers={ hxHeaders }
|
|
>
|
|
Delete
|
|
</button>
|
|
@GuestbookDashboardUpdateButtonPart(data, w, c)
|
|
}
|
|
</div>
|
|
</header>
|
|
<div class="comment-content">
|
|
<p>
|
|
{ c.CommentText }
|
|
</p>
|
|
</div>
|
|
<hr role="separator"/>
|
|
</article>
|
|
}
|
|
|
|
templ commentForm(form forms.CommentCreateForm) {
|
|
<fieldset>
|
|
<legend>Leave a comment</legend>
|
|
<div class="form-group">
|
|
<label for="authorname">Name <span aria-label="required">*</span></label>
|
|
{{ error, exists := form.FieldErrors["authorName"] }}
|
|
if exists {
|
|
<label class="error">{ error }</label>
|
|
}
|
|
<input type="text" name="authorname" id="authorname" required aria-describedby="authorname-help"/>
|
|
<small id="authorname-help">Your name or handle</small>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="authoremail">Email (Optional)</label>
|
|
{{ error, exists = form.FieldErrors["authorEmail"] }}
|
|
if exists {
|
|
<label class="error">{ error }</label>
|
|
}
|
|
<input type="email" name="authoremail" id="authoremail" aria-describedby="authoremail-help"/>
|
|
<small id="authoremail-help">Your email address will only be shared with the guestbook's owner</small>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="authorsite">Website URL (Optional)</label>
|
|
{{ error, exists = form.FieldErrors["authorSite"] }}
|
|
if exists {
|
|
<label class="error">{ error }</label>
|
|
}
|
|
<input type="url" name="authorsite" id="authorsite" aria-describedby="authorsite-help"/>
|
|
<small id="authorsite-help">Link to your website or social profile</small>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="content">Comment <span aria-label="required">*</span></label>
|
|
{{ error, exists = form.FieldErrors["content"] }}
|
|
if exists {
|
|
<label class="error">{ error }</label>
|
|
}
|
|
<textarea name="content" id="content" required aria-describedby="content-help"></textarea>
|
|
<small id="content-help">Share your thoughts, feedback, or just say hello!</small>
|
|
</div>
|
|
<div class="form-group">
|
|
<button type="submit">Submit Comment</button>
|
|
</div>
|
|
</fieldset>
|
|
}
|
|
|
|
templ GuestbookView(title string, data CommonData, website models.Website, guestbook models.Guestbook, comments []models.GuestbookComment, form forms.CommentCreateForm) {
|
|
{{ postUrl := fmt.Sprintf("/websites/%s/guestbook/comments/create", shortIdToSlug(website.ShortId)) }}
|
|
if data.IsHtmx {
|
|
@commentForm(form)
|
|
} else {
|
|
<html>
|
|
<head>
|
|
<title>{ title }</title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
<link href="/static/css/style.css" rel="stylesheet"/>
|
|
<script src="/static/js/main.js" defer></script>
|
|
</head>
|
|
<body>
|
|
<main role="main">
|
|
<section aria-labelledby="guestbook-heading">
|
|
<h1>{ website.Name } Guestbook</h1>
|
|
{ data.Flash }
|
|
<form action={ templ.URL(postUrl) } method="post">
|
|
<input type="hidden" name="csrf_token" value={ data.CSRFToken }/>
|
|
@commentForm(form)
|
|
</form>
|
|
</section>
|
|
<section id="comments" aria-labelledby="comments-heading">
|
|
<h2 id="comments-heading">Comments</h2>
|
|
if len(comments) == 0 {
|
|
<p>No comments yet!</p>
|
|
}
|
|
for i, c := range comments {
|
|
{{ commentAuthorRole := fmt.Sprintf("comment-author-%d", i+1) }}
|
|
<article class="comment" role="article" aria-labelledby={ commentAuthorRole }>
|
|
<header class="comment-header">
|
|
<h3 id={ commentAuthorRole } class="comment-author">
|
|
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>
|
|
</header>
|
|
<div class="comment-content">
|
|
<p>
|
|
{ c.CommentText }
|
|
</p>
|
|
</div>
|
|
</article>
|
|
}
|
|
</section>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
}
|
|
}
|
|
|
|
templ settingRadio(selected bool, name, id, value string) {
|
|
<input type="radio" name={ name } id={ id } value={ value } selected?={ selected }/>
|
|
}
|
|
|
|
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) {
|
|
@base("All Guestbooks", data) {
|
|
<div>
|
|
<p>
|
|
This page exists only for testing the service.
|
|
</p>
|
|
<ul>
|
|
for _, w := range websites {
|
|
<li>
|
|
{{ gbUrl := fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(w.ShortId)) }}
|
|
<a href={ templ.URL(gbUrl) } target="_blank">{ w.Name }</a>
|
|
</li>
|
|
}
|
|
</ul>
|
|
</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>
|
|
}
|