dev: automated commit - 2025-06-17 16:15:21

This commit is contained in:
Mariano Z. 2025-06-17 16:15:21 -03:00
parent 73e91db78b
commit 27775e6b29
16 changed files with 1860 additions and 1240 deletions

34
templates/alert.templ Normal file
View file

@ -0,0 +1,34 @@
package templates
templ Alert(id, alertType, message string, dismissible bool) {
<div
id={ id }
class={ "alert", "alert-" + alertType, templ.KV("alert-dismissible", dismissible), templ.KV("d-none", message == "") }
role="alert"
>
if message != "" {
{ message }
}
if dismissible {
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
}
</div>
}
// Helper components for common alert types
templ ErrorAlert(id, message string) {
@Alert(id, "danger", message, false)
}
templ SuccessAlert(id, message string) {
@Alert(id, "success", message, true)
}
templ WarningAlert(id, message string) {
@Alert(id, "warning", message, true)
}
templ InfoAlert(id, message string) {
@Alert(id, "info", message, true)
}

214
templates/alert_templ.go Normal file
View file

@ -0,0 +1,214 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.898
package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Alert(id, alertType, message string, dismissible bool) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{"alert", "alert-" + alertType, templ.KV("alert-dismissible", dismissible), templ.KV("d-none", message == "")}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(id)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/alert.templ`, Line: 6, Col: 9}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/alert.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\" role=\"alert\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if message != "" {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/alert.templ`, Line: 11, Col: 12}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if dismissible {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// Helper components for common alert types
func ErrorAlert(id, message 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_Var6 := templ.GetChildren(ctx)
if templ_7745c5c3_Var6 == nil {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = Alert(id, "danger", message, false).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func SuccessAlert(id, message 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_Var7 := templ.GetChildren(ctx)
if templ_7745c5c3_Var7 == nil {
templ_7745c5c3_Var7 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = Alert(id, "success", message, true).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func WarningAlert(id, message 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_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = Alert(id, "warning", message, true).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func InfoAlert(id, message 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_Var9 := templ.GetChildren(ctx)
if templ_7745c5c3_Var9 == nil {
templ_7745c5c3_Var9 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = Alert(id, "info", message, true).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate

View file

@ -43,17 +43,16 @@ templ Index(props IndexProps) {
<h1>{ props.Title }</h1>
<div class="current-ip d-flex align-items-center">
<span class="me-2">Current IP:</span>
<span id="current-ip" class="fw-bold">{ props.CurrentIP }</span>
<button
class="btn btn-sm btn-outline-secondary ms-2"
title="Refresh current IP"
hx-get="/refresh-ip"
hx-target="#current-ip"
hx-indicator="#refresh-spinner"
<span id="current-ip" x-init class="fw-bold">{ props.CurrentIP }</span>
<a
href="/refresh-ip"
x-target="current-ip"
class="btn btn-sm btn-outline-secondary ms-2 d-inline-flex align-items-center"
@ajax:before="$el.querySelector('.bi-arrow-clockwise').classList.add('spin')"
@ajax:after="$el.querySelector('.bi-arrow-clockwise').classList.remove('spin')"
>
<i class="bi bi-arrow-clockwise"></i>
<span id="refresh-spinner" class="htmx-indicator spinner-border spinner-border-sm ms-1"></span>
</button>
</a>
</div>
</div>
if !props.IsConfigured {
@ -62,12 +61,9 @@ templ Index(props IndexProps) {
@ConfigStatus(props.Config)
@DNSRecordsSection(props.Records, props.CurrentIP)
}
@ConfigModal(props.Config, props.UpdateFreqs)
@RecordModal(props.Config.Domain)
</div>
</div>
</div>
<div class="toast-container"></div>
}
}
@ -86,16 +82,34 @@ templ ConfigWarning() {
}
templ ConfigStatus(config ConfigData) {
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card mb-4" id="config-status">
<div
class="card-header d-flex justify-content-between align-items-center"
x-init
x-data="{ editLoading: false, deleteLoading: false }"
@ajax:success="$dispatch('dialog:open')"
>
<h5 class="mb-0">Configuration</h5>
<button
class="btn btn-sm btn-outline-primary"
data-bs-toggle="modal"
data-bs-target="#configModal"
<a
href="/config"
@ajax:before="editLoading = true"
@ajax:success="$dispatch('dialog:open')"
@ajax:after="editLoading = false"
@ajax:error="editLoading = false"
x-target="contact"
class="btn btn-sm btn-outline-primary me-2"
:disabled="editLoading || deleteLoading"
>
Edit
</button>
<template x-if="!editLoading">
<span class="ms-1">
Edit
<i class="bi bi-pencil"></i>
</span>
</template>
<template x-if="editLoading">
<span class="spinner-border spinner-border-sm"></span>
</template>
</a>
</div>
<div class="card-body">
<div class="row">
@ -118,25 +132,57 @@ templ DNSRecordsSection(records []DNSRecord, currentIP string) {
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">DNS Records</h5>
<div>
<button
class="btn btn-sm btn-success me-2"
hx-post="/update-all-records"
hx-target="#dns-records-table"
hx-confirm="Are you sure you want to update all A records to your current IP?"
hx-indicator="#update-all-spinner"
<div x-data="{ updating: false, addingRecord: false }">
<form
method="post"
action="/update-all-records"
x-target="dns-records-table"
@ajax:before="confirm('Are you sure you want to update all A records to your current IP?') || $event.preventDefault(); updating = true"
@ajax:after="updating = false"
@ajax:error="updating = false"
style="display: inline;"
>
<i class="bi bi-arrow-repeat"></i> Update All to Current IP
<span id="update-all-spinner" class="htmx-indicator spinner-border spinner-border-sm ms-1"></span>
</button>
<button
class="btn btn-sm btn-primary"
data-bs-toggle="modal"
data-bs-target="#recordModal"
onclick="resetRecordForm()"
<button
class="btn btn-sm btn-success me-2"
type="submit"
:disabled="updating || addingRecord"
>
<template x-if="!updating">
<span class="d-flex align-items-center">
<i class="bi bi-arrow-repeat me-1"></i>
Update All to Current IP
</span>
</template>
<template x-if="updating">
<span class="d-flex align-items-center">
<span class="spinner-border spinner-border-sm me-2"></span>
Updating All Records...
</span>
</template>
</button>
</form>
<a
href="/records/new"
x-target="contact"
@ajax:before="addingRecord = true; $dispatch('dialog:open')"
@ajax:after="addingRecord = false"
@ajax:error="addingRecord = false"
class="btn btn-primary"
:disabled="updating || addingRecord"
>
<i class="bi bi-plus-lg"></i> Add Record
</button>
<template x-if="!addingRecord">
<span class="d-flex align-items-center">
<i class="bi bi-plus-lg me-1"></i>
Add Record
</span>
</template>
<template x-if="addingRecord">
<span class="d-flex align-items-center">
<span class="spinner-border spinner-border-sm me-2"></span>
Loading...
</span>
</template>
</a>
</div>
</div>
<div class="card-body p-0">
@ -174,7 +220,7 @@ templ DNSRecordsTable(records []DNSRecord, currentIP string) {
}
templ DNSRecordRow(record DNSRecord, currentIP string) {
<tr>
<tr x-data="{ editLoading: false, deleteLoading: false }">
<td>{ record.Type }</td>
<td>{ record.Name }</td>
<td>
@ -200,23 +246,46 @@ templ DNSRecordRow(record DNSRecord, currentIP string) {
}
</td>
<td>
<button
class="btn btn-sm btn-outline-primary me-1"
hx-get={ fmt.Sprintf("/edit-record/%s", record.ID) }
hx-target="#record-modal-content"
hx-on::after-request="if(event.detail.successful) bootstrap.Modal.getOrCreateInstance(document.getElementById('recordModal')).show()"
<a
href={ templ.URL(fmt.Sprintf("/edit-record/%s", record.ID)) }
@ajax:before="editLoading = true"
@ajax:success="$dispatch('dialog:open')"
@ajax:after="editLoading = false"
@ajax:error="editLoading = false"
x-target="contact"
class="btn btn-sm btn-outline-primary me-2"
:disabled="editLoading || deleteLoading"
>
<i class="bi bi-pencil"></i>
</button>
<button
class="btn btn-sm btn-outline-danger"
hx-delete={ fmt.Sprintf("/records/%s", record.ID) }
hx-target="closest tr"
hx-swap="outerHTML"
hx-confirm={ fmt.Sprintf("Are you sure you want to delete the record for \"%s\"?", record.Name) }
<template x-if="!editLoading">
<i class="bi bi-pencil"></i>
</template>
<template x-if="editLoading">
<span class="spinner-border spinner-border-sm"></span>
</template>
</a>
<form
method="delete"
action={ templ.URL(fmt.Sprintf("/records/%s", record.ID)) }
x-target="closest tr"
@ajax:before={ fmt.Sprintf(`confirm('Are you sure you want to delete the record for "%s"?') || $event.preventDefault(); deleteLoading = true`, record.Name) }
@ajax:after="deleteLoading = false"
@ajax:error="deleteLoading = false"
@ajax:success="$el.closest('tr').remove()"
style="display: inline;"
>
<i class="bi bi-trash"></i>
</button>
<button
class="btn btn-sm btn-outline-danger"
type="submit"
:disabled="editLoading || deleteLoading"
>
<template x-if="!deleteLoading">
<i class="bi bi-trash"></i>
</template>
<template x-if="deleteLoading">
<span class="spinner-border spinner-border-sm"></span>
</template>
</button>
</form>
</td>
</tr>
}

View file

@ -88,20 +88,20 @@ func Index(props IndexProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</h1><div class=\"current-ip d-flex align-items-center\"><span class=\"me-2\">Current IP:</span> <span id=\"current-ip\" class=\"fw-bold\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</h1><div class=\"current-ip d-flex align-items-center\"><span class=\"me-2\">Current IP:</span> <span id=\"current-ip\" x-init class=\"fw-bold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.CurrentIP)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 46, Col: 62}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 46, Col: 69}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span> <button class=\"btn btn-sm btn-outline-secondary ms-2\" title=\"Refresh current IP\" hx-get=\"/refresh-ip\" hx-target=\"#current-ip\" hx-indicator=\"#refresh-spinner\"><i class=\"bi bi-arrow-clockwise\"></i> <span id=\"refresh-spinner\" class=\"htmx-indicator spinner-border spinner-border-sm ms-1\"></span></button></div></div>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span> <a href=\"/refresh-ip\" x-target=\"current-ip\" class=\"btn btn-sm btn-outline-secondary ms-2 d-inline-flex align-items-center\" @ajax:before=\"$el.querySelector('.bi-arrow-clockwise').classList.add('spin')\" @ajax:after=\"$el.querySelector('.bi-arrow-clockwise').classList.remove('spin')\"><i class=\"bi bi-arrow-clockwise\"></i></a></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -124,15 +124,7 @@ func Index(props IndexProps) templ.Component {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = ConfigModal(props.Config, props.UpdateFreqs).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = RecordModal(props.Config.Domain).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</div></div></div><div class=\"toast-container\"></div>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -196,14 +188,14 @@ func ConfigStatus(config ConfigData) templ.Component {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"card mb-4\"><div class=\"card-header d-flex justify-content-between align-items-center\"><h5 class=\"mb-0\">Configuration</h5><button class=\"btn btn-sm btn-outline-primary\" data-bs-toggle=\"modal\" data-bs-target=\"#configModal\">Edit</button></div><div class=\"card-body\"><div class=\"row\"><div class=\"col-md-4\"><strong>Domain:</strong> <span>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"card mb-4\" id=\"config-status\"><div class=\"card-header d-flex justify-content-between align-items-center\" x-init x-data=\"{ editLoading: false, deleteLoading: false }\" @ajax:success=\"$dispatch('dialog:open')\"><h5 class=\"mb-0\">Configuration</h5><a href=\"/config\" @ajax:before=\"editLoading = true\" @ajax:success=\"$dispatch('dialog:open')\" @ajax:after=\"editLoading = false\" @ajax:error=\"editLoading = false\" x-target=\"contact\" class=\"btn btn-sm btn-outline-primary me-2\" :disabled=\"editLoading || deleteLoading\"><template x-if=\"!editLoading\"><span class=\"ms-1\">Edit <i class=\"bi bi-pencil\"></i></span></template><template x-if=\"editLoading\"><span class=\"spinner-border spinner-border-sm\"></span></template></a></div><div class=\"card-body\"><div class=\"row\"><div class=\"col-md-4\"><strong>Domain:</strong> <span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(config.Domain)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 103, Col: 51}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 117, Col: 51}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@ -216,7 +208,7 @@ func ConfigStatus(config ConfigData) templ.Component {
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(config.ZoneID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 106, Col: 52}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 120, Col: 52}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
@ -229,7 +221,7 @@ func ConfigStatus(config ConfigData) templ.Component {
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(formatUpdateSchedule(config.UpdatePeriod))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 110, Col: 54}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 124, Col: 54}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
@ -264,7 +256,7 @@ func DNSRecordsSection(records []DNSRecord, currentIP string) templ.Component {
templ_7745c5c3_Var10 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"card\"><div class=\"card-header d-flex justify-content-between align-items-center\"><h5 class=\"mb-0\">DNS Records</h5><div><button class=\"btn btn-sm btn-success me-2\" hx-post=\"/update-all-records\" hx-target=\"#dns-records-table\" hx-confirm=\"Are you sure you want to update all A records to your current IP?\" hx-indicator=\"#update-all-spinner\"><i class=\"bi bi-arrow-repeat\"></i> Update All to Current IP <span id=\"update-all-spinner\" class=\"htmx-indicator spinner-border spinner-border-sm ms-1\"></span></button> <button class=\"btn btn-sm btn-primary\" data-bs-toggle=\"modal\" data-bs-target=\"#recordModal\" onclick=\"resetRecordForm()\"><i class=\"bi bi-plus-lg\"></i> Add Record</button></div></div><div class=\"card-body p-0\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"card\"><div class=\"card-header d-flex justify-content-between align-items-center\"><h5 class=\"mb-0\">DNS Records</h5><div x-data=\"{ updating: false, addingRecord: false }\"><form method=\"post\" action=\"/update-all-records\" x-target=\"dns-records-table\" @ajax:before=\"confirm('Are you sure you want to update all A records to your current IP?') || $event.preventDefault(); updating = true\" @ajax:after=\"updating = false\" @ajax:error=\"updating = false\" style=\"display: inline;\"><button class=\"btn btn-sm btn-success me-2\" type=\"submit\" :disabled=\"updating || addingRecord\"><template x-if=\"!updating\"><span class=\"d-flex align-items-center\"><i class=\"bi bi-arrow-repeat me-1\"></i> Update All to Current IP</span></template><template x-if=\"updating\"><span class=\"d-flex align-items-center\"><span class=\"spinner-border spinner-border-sm me-2\"></span> Updating All Records...</span></template></button></form><a href=\"/records/new\" x-target=\"contact\" @ajax:before=\"addingRecord = true; $dispatch('dialog:open')\" @ajax:after=\"addingRecord = false\" @ajax:error=\"addingRecord = false\" class=\"btn btn-primary\" :disabled=\"updating || addingRecord\"><template x-if=\"!addingRecord\"><span class=\"d-flex align-items-center\"><i class=\"bi bi-plus-lg me-1\"></i> Add Record</span></template><template x-if=\"addingRecord\"><span class=\"d-flex align-items-center\"><span class=\"spinner-border spinner-border-sm me-2\"></span> Loading...</span></template></a></div></div><div class=\"card-body p-0\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -347,14 +339,14 @@ func DNSRecordRow(record DNSRecord, currentIP string) templ.Component {
templ_7745c5c3_Var12 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<tr><td>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<tr x-data=\"{ editLoading: false, deleteLoading: false }\"><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(record.Type)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 178, Col: 19}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 224, Col: 19}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
@ -367,7 +359,7 @@ func DNSRecordRow(record DNSRecord, currentIP string) templ.Component {
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(record.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 179, Col: 19}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 225, Col: 19}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
@ -380,7 +372,7 @@ func DNSRecordRow(record DNSRecord, currentIP string) templ.Component {
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(record.Content)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 181, Col: 19}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 227, Col: 19}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
@ -416,7 +408,7 @@ func DNSRecordRow(record DNSRecord, currentIP string) templ.Component {
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%ds", record.TTL))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 194, Col: 36}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 240, Col: 36}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
@ -433,46 +425,46 @@ func DNSRecordRow(record DNSRecord, currentIP string) templ.Component {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</td><td><button class=\"btn btn-sm btn-outline-primary me-1\" hx-get=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</td><td><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("/edit-record/%s", record.ID))
var templ_7745c5c3_Var17 templ.SafeURL
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL(fmt.Sprintf("/edit-record/%s", record.ID)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 205, Col: 54}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 250, Col: 63}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" hx-target=\"#record-modal-content\" hx-on::after-request=\"if(event.detail.successful) bootstrap.Modal.getOrCreateInstance(document.getElementById('recordModal')).show()\"><i class=\"bi bi-pencil\"></i></button> <button class=\"btn btn-sm btn-outline-danger\" hx-delete=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" @ajax:before=\"editLoading = true\" @ajax:success=\"$dispatch('dialog:open')\" @ajax:after=\"editLoading = false\" @ajax:error=\"editLoading = false\" x-target=\"contact\" class=\"btn btn-sm btn-outline-primary me-2\" :disabled=\"editLoading || deleteLoading\"><template x-if=\"!editLoading\"><i class=\"bi bi-pencil\"></i></template><template x-if=\"editLoading\"><span class=\"spinner-border spinner-border-sm\"></span></template></a><form method=\"delete\" action=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var18 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("/records/%s", record.ID))
var templ_7745c5c3_Var18 templ.SafeURL
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL(fmt.Sprintf("/records/%s", record.ID)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 213, Col: 53}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 268, Col: 61}
}
_, 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, 28, "\" hx-target=\"closest tr\" hx-swap=\"outerHTML\" hx-confirm=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "\" x-target=\"closest tr\" @ajax:before=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var19 string
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("Are you sure you want to delete the record for \"%s\"?", record.Name))
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(`confirm('Are you sure you want to delete the record for "%s"?') || $event.preventDefault(); deleteLoading = true`, record.Name))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 216, Col: 99}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/index.templ`, Line: 270, Col: 159}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "\"><i class=\"bi bi-trash\"></i></button></td></tr>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "\" @ajax:after=\"deleteLoading = false\" @ajax:error=\"deleteLoading = false\" @ajax:success=\"$el.closest('tr').remove()\" style=\"display: inline;\"><button class=\"btn btn-sm btn-outline-danger\" type=\"submit\" :disabled=\"editLoading || deleteLoading\"><template x-if=\"!deleteLoading\"><i class=\"bi bi-trash\"></i></template><template x-if=\"deleteLoading\"><span class=\"spinner-border spinner-border-sm\"></span></template></button></form></td></tr>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View file

@ -8,6 +8,16 @@ func Render(w io.Writer, component templ.Component) error {
return component.Render(context.Background(), w)
}
// RenderMultiple renders multiple components to an io.Writer in sequence
func RenderMultiple(w io.Writer, components ...templ.Component) error {
for _, component := range components {
if err := component.Render(context.Background(), w); err != nil {
return err
}
}
return nil
}
// Layout is the base layout for all pages
templ Layout(title string) {
<!DOCTYPE html>
@ -16,6 +26,8 @@ templ Layout(title string) {
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{ title }</title>
<script defer src="https://cdn.jsdelivr.net/npm/@imacrayon/alpine-ajax@0.12.2/dist/cdn.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.1/dist/cdn.min.js"></script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
@ -24,8 +36,9 @@ templ Layout(title string) {
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css"
/>
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<style>
/* Base Styles */
body {
padding-top: 20px;
background-color: #f8f9fa;
@ -47,62 +60,185 @@ templ Layout(title string) {
font-size: 0.8em;
margin-left: 10px;
}
.htmx-indicator {
opacity: 0;
transition: opacity 300ms ease-in;
.spin {
animation: spin 1s linear infinite;
}
.htmx-request .htmx-indicator {
opacity: 1;
}
.htmx-request.htmx-indicator {
opacity: 1;
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* Modal Styles */
dialog {
border: none !important;
outline: none !important;
border-radius: 0;
padding: 0;
margin: 0;
background: transparent;
box-shadow: none;
max-width: none;
max-height: none;
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
}
dialog[open] {
border: none !important;
outline: none !important;
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
animation: fadeIn 0.2s ease-out;
}
.modal-container {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 1rem;
animation: modalShow 0.3s ease-out;
}
.modal-content {
background: white;
border-radius: 12px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
width: 100%;
max-width: 600px;
max-height: 90vh;
overflow: hidden;
transform: scale(1);
animation: modalSlideIn 0.3s ease-out;
}
.modal-header {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-bottom: 1px solid #dee2e6;
padding: 1.5rem;
display: flex;
align-items: center;
justify-content: space-between;
}
.modal-title {
margin: 0;
font-weight: 600;
color: #495057;
font-size: 1.25rem;
}
.modal-body {
padding: 2rem;
max-height: 60vh;
overflow-y: auto;
}
.modal-footer {
background: #f8f9fa;
border-top: 1px solid #dee2e6;
padding: 1.5rem;
display: flex;
gap: 0.75rem;
justify-content: flex-end;
}
/* Enhanced form styling within modals */
.modal-body .form-label {
color: #495057;
margin-bottom: 0.75rem;
}
.modal-body .form-control,
.modal-body .form-select {
border: 2px solid #e9ecef;
border-radius: 8px;
padding: 0.75rem;
transition: all 0.2s ease;
}
.modal-body .form-control:focus,
.modal-body .form-select:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.1);
}
.modal-body .input-group-text {
border: 2px solid #e9ecef;
border-left: none;
background: #f8f9fa;
font-weight: 500;
}
.modal-body .form-check {
border: 1px solid #e9ecef;
}
.modal-body .form-text {
font-size: 0.875rem;
color: #6c757d;
margin-top: 0.5rem;
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes modalShow {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes modalSlideIn {
from {
transform: scale(0.95) translateY(-20px);
opacity: 0;
}
to {
transform: scale(1) translateY(0);
opacity: 1;
}
}
/* Responsive adjustments */
@media (max-width: 768px) {
.modal-container {
padding: 0.5rem;
}
.modal-content {
max-height: 95vh;
border-radius: 8px;
}
.modal-header,
.modal-body,
.modal-footer {
padding: 1rem;
}
.modal-body {
max-height: 70vh;
}
}
</style>
</head>
<body>
<body id="body">
<div class="toast-container position-fixed top-0 end-0 p-3">
<ul x-sync id="notification_list" x-merge="prepend" role="status" class="list-unstyled"></ul>
</div>
{ children... }
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Simple toast function for HTMX responses
document.body.addEventListener('htmx:afterRequest', function(evt) {
const xhr = evt.detail.xhr;
if (xhr.status >= 200 && xhr.status < 300) {
const successMessage = xhr.getResponseHeader('HX-Success-Message');
if (successMessage) {
showToast(successMessage, 'success');
}
} else {
const errorMessage = xhr.getResponseHeader('HX-Error-Message') || 'An error occurred';
showToast(errorMessage, 'danger');
}
});
function showToast(message, type = "success") {
const toastContainer = document.querySelector(".toast-container");
const toast = document.createElement("div");
toast.className = `toast align-items-center text-white bg-${type}`;
toast.setAttribute("role", "alert");
toast.setAttribute("aria-live", "assertive");
toast.setAttribute("aria-atomic", "true");
toast.innerHTML = `
<div class="d-flex">
<div class="toast-body">${message}</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
`;
toastContainer.appendChild(toast);
const bsToast = new bootstrap.Toast(toast);
bsToast.show();
toast.addEventListener("hidden.bs.toast", () => {
toast.remove();
});
}
</script>
<dialog id="global-dialog" x-init @dialog:open.window="$el.showModal()">
<div id="contact"></div>
</dialog>
</body>
</html>
}

File diff suppressed because one or more lines are too long

View file

@ -3,253 +3,314 @@ package templates
import "fmt"
templ ConfigModal(config ConfigData, frequencies []UpdateFrequency) {
<div
class="modal fade"
id="configModal"
tabindex="-1"
aria-labelledby="configModalLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="configModalLabel">Configuration</h5>
<div id="contact" class="modal-container">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Configuration Settings</h5>
<button
type="button"
class="btn-close"
@click="$el.closest('dialog').close()"
aria-label="Close"
></button>
</div>
<form
x-target="config-status"
method="post"
action="/config"
@ajax:success="$el.closest('dialog').close()"
x-data="{ saving: false }"
@ajax:before="saving = true"
@ajax:after="saving = false"
@ajax:error="saving = false"
>
<div class="modal-body">
<div class="mb-3">
<label for="api-token" class="form-label fw-semibold">
<i class="bi bi-key-fill text-primary me-2"></i>
Cloudflare API Token
</label>
<input
type="password"
class="form-control"
id="api-token"
name="api_token"
value={ config.ApiToken }
placeholder="Enter your Cloudflare API token"
required
/>
<div class="form-text">
<i class="bi bi-info-circle me-1"></i>
Create a token with <code>Zone.DNS:Edit</code> permissions in
the Cloudflare dashboard.
</div>
</div>
<div class="mb-3">
<label for="zone-id-input" class="form-label fw-semibold">
<i class="bi bi-globe text-info me-2"></i>
Zone ID
</label>
<input
type="text"
class="form-control"
id="zone-id-input"
name="zone_id"
value={ config.ZoneID }
placeholder="e.g., 1234567890abcdef1234567890abcdef"
required
/>
<div class="form-text">
<i class="bi bi-info-circle me-1"></i>
Found in the Cloudflare dashboard under your domain's overview page.
</div>
</div>
<div class="mb-3">
<label for="domain-input" class="form-label fw-semibold">
<i class="bi bi-link-45deg text-success me-2"></i>
Domain
</label>
<input
type="text"
class="form-control"
id="domain-input"
name="domain"
value={ config.Domain }
placeholder="e.g., example.com"
required
/>
</div>
<div class="mb-3">
<label for="update-period" class="form-label fw-semibold">
<i class="bi bi-clock text-warning me-2"></i>
Update Frequency
</label>
<select class="form-select" id="update-period" name="update_period">
for _, freq := range frequencies {
<option value={ freq.Value } selected?={ freq.Value == config.UpdatePeriod }>
{ freq.Label }
</option>
}
</select>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
class="btn btn-secondary"
@click="$el.closest('dialog').close()"
>
<i class="bi bi-x-lg me-1"></i>
Cancel
</button>
<button
type="submit"
class="btn btn-primary"
:disabled="saving"
>
<template x-if="!saving">
<span class="d-flex align-items-center">
<i class="bi bi-check-lg me-2"></i>
Save Configuration
</span>
</template>
<template x-if="saving">
<span class="d-flex align-items-center">
<span class="spinner-border spinner-border-sm me-2"></span>
Saving...
</span>
</template>
</button>
</div>
<form hx-post="/config" hx-target="body" hx-swap="outerHTML">
<div class="modal-body">
<div class="mb-3">
<label for="api-token" class="form-label">Cloudflare API Token</label>
<input
type="password"
class="form-control"
id="api-token"
name="api_token"
value={ config.ApiToken }
required
/>
<div class="form-text">
Create a token with <code>Zone.DNS:Edit</code> permissions in
the Cloudflare dashboard.
</div>
</div>
<div class="mb-3">
<label for="zone-id-input" class="form-label">Zone ID</label>
<input
type="text"
class="form-control"
id="zone-id-input"
name="zone_id"
value={ config.ZoneID }
required
/>
<div class="form-text">
Found in the Cloudflare dashboard under your domain's overview page.
</div>
</div>
<div class="mb-3">
<label for="domain-input" class="form-label">Domain</label>
<input
type="text"
class="form-control"
id="domain-input"
name="domain"
value={ config.Domain }
required
/>
</div>
<div class="mb-3">
<label for="update-period" class="form-label">Update Frequency</label>
<select class="form-select" id="update-period" name="update_period">
for _, freq := range frequencies {
<option value={ freq.Value } selected?={ freq.Value == config.UpdatePeriod }>
{ freq.Label }
</option>
}
</select>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
Cancel
</button>
<button type="submit" class="btn btn-primary">
Save
<span class="htmx-indicator spinner-border spinner-border-sm ms-1"></span>
</button>
</div>
</form>
</div>
</div>
</div>
}
templ RecordModal(domain string) {
<div
class="modal fade"
id="recordModal"
tabindex="-1"
aria-labelledby="recordModalLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div id="record-modal-content" class="modal-content">
@RecordForm("Add DNS Record", "", domain, DNSRecord{Type: "A", TTL: 1})
</div>
</form>
</div>
</div>
}
templ RecordForm(title, recordID, domain string, record DNSRecord) {
<div class="modal-header">
<h5 class="modal-title">{ title }</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<form
if recordID != "" {
hx-put={ fmt.Sprintf("/records/%s", recordID) }
} else {
hx-post="/records"
}
hx-target="#dns-records-table"
hx-on::after-request="if(event.detail.successful) bootstrap.Modal.getInstance(document.getElementById('recordModal')).hide()"
>
<div class="modal-body">
<div class="mb-3">
<label for="record-name" class="form-label">Name</label>
<div class="input-group">
<input
type="text"
class="form-control"
id="record-name"
name="name"
placeholder="subdomain"
value={ getRecordName(record.Name, domain) }
required
/>
<span class="input-group-text">.{ domain }</span>
</div>
<div class="form-text">Use @ for the root domain</div>
<div id="contact" class="modal-container">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="bi bi-dns text-primary me-2"></i>
{ title }
</h5>
<button
type="button"
class="btn-close"
@click="$el.closest('dialog').close()"
aria-label="Close"
></button>
</div>
<div class="mb-3">
<label for="record-type" class="form-label">Type</label>
<select
class="form-select"
id="record-type"
name="type"
onchange="toggleMyIPOption()"
>
<option value="A" selected?={ record.Type == "A" }>A</option>
<option value="AAAA" selected?={ record.Type == "AAAA" }>AAAA</option>
<option value="CNAME" selected?={ record.Type == "CNAME" }>CNAME</option>
<option value="TXT" selected?={ record.Type == "TXT" }>TXT</option>
<option value="MX" selected?={ record.Type == "MX" }>MX</option>
</select>
<div id="error-message" class="alert alert-danger d-none mx-3 mt-3" role="alert">
<i class="bi bi-exclamation-triangle-fill me-2"></i>
<span class="error-text"></span>
</div>
<div class="mb-3" id="content-group">
<label for="record-content" class="form-label">Content</label>
<input
type="text"
class="form-control"
id="record-content"
name="content"
value={ record.Content }
required
/>
</div>
<div class="mb-3 form-check" id="use-my-ip-group" style="display: none;">
<input
type="checkbox"
class="form-check-input"
id="use-my-ip"
name="use_my_ip"
onchange="toggleContentField()"
/>
<label class="form-check-label" for="use-my-ip">Use my current IP address</label>
</div>
<div class="mb-3">
<label for="record-ttl" class="form-label">TTL</label>
<select class="form-select" id="record-ttl" name="ttl">
<option value="1" selected?={ record.TTL == 1 }>Auto</option>
<option value="120" selected?={ record.TTL == 120 }>2 minutes</option>
<option value="300" selected?={ record.TTL == 300 }>5 minutes</option>
<option value="600" selected?={ record.TTL == 600 }>10 minutes</option>
<option value="1800" selected?={ record.TTL == 1800 }>30 minutes</option>
<option value="3600" selected?={ record.TTL == 3600 }>1 hour</option>
<option value="7200" selected?={ record.TTL == 7200 }>2 hours</option>
<option value="18000" selected?={ record.TTL == 18000 }>5 hours</option>
<option value="43200" selected?={ record.TTL == 43200 }>12 hours</option>
<option value="86400" selected?={ record.TTL == 86400 }>1 day</option>
</select>
</div>
<div class="mb-3 form-check">
<input
type="checkbox"
class="form-check-input"
id="record-proxied"
name="proxied"
checked?={ record.Proxied }
/>
<label class="form-check-label" for="record-proxied">Proxied through Cloudflare</label>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
<form
if recordID != "" {
method="put"
action={ templ.URL(fmt.Sprintf("/records/%s", recordID)) }
} else {
method="post"
action="/records"
}
x-target="dns-records-table"
x-target.error="none"
@ajax:success="$el.closest('dialog').close()"
x-data="{ saving: false }"
@ajax:before="saving = true"
@ajax:after="saving = false"
@ajax:error="saving = false"
>
Cancel
</button>
<button type="submit" class="btn btn-primary">
Save
<span class="htmx-indicator spinner-border spinner-border-sm ms-1"></span>
</button>
<div class="modal-body">
<div class="row">
<div class="col-md-8 mb-3">
<label for="record-name" class="form-label fw-semibold">
<i class="bi bi-tag text-info me-2"></i>
Record Name
</label>
<div class="input-group">
<input
type="text"
class="form-control"
id="record-name"
name="name"
placeholder="subdomain"
value={ getRecordName(record.Name, domain) }
required
/>
<span class="input-group-text bg-light text-muted">.{ domain }</span>
</div>
<div class="form-text">
<i class="bi bi-info-circle me-1"></i>
Use <code>{ "@" }</code> { "for" } the root domain
</div>
</div>
<div class="col-md-4 mb-3">
<label for="record-type" class="form-label fw-semibold">
<i class="bi bi-diagram-3 text-success me-2"></i>
Type
</label>
<select
class="form-select"
id="record-type"
name="type"
onchange="toggleMyIPOption()"
>
<option value="A" selected?={ record.Type == "A" }>A (IPv4)</option>
<option value="AAAA" selected?={ record.Type == "AAAA" }>AAAA (IPv6)</option>
<option value="CNAME" selected?={ record.Type == "CNAME" }>CNAME</option>
<option value="TXT" selected?={ record.Type == "TXT" }>TXT</option>
<option value="MX" selected?={ record.Type == "MX" }>MX</option>
</select>
</div>
</div>
<div class="mb-3" id="content-group">
<label for="record-content" class="form-label fw-semibold">
<i class="bi bi-file-text text-warning me-2"></i>
Content
</label>
<input
type="text"
class="form-control"
id="record-content"
name="content"
value={ record.Content }
placeholder="Enter the record value"
required
/>
</div>
<div class="mb-3 form-check bg-light p-3 rounded" id="use-my-ip-group" style="display: none;">
<input
type="checkbox"
class="form-check-input"
id="use-my-ip"
name="use_my_ip"
onchange="toggleContentField()"
/>
<label class="form-check-label fw-semibold" for="use-my-ip">
<i class="bi bi-geo-alt text-primary me-2"></i>
Use my current IP address
</label>
<div class="form-text">
Automatically use your current public IP address
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="record-ttl" class="form-label fw-semibold">
<i class="bi bi-clock-history text-secondary me-2"></i>
TTL (Time to Live)
</label>
<select class="form-select" id="record-ttl" name="ttl">
<option value="1" selected?={ record.TTL == 1 }>Auto</option>
<option value="120" selected?={ record.TTL == 120 }>2 minutes</option>
<option value="300" selected?={ record.TTL == 300 }>5 minutes</option>
<option value="600" selected?={ record.TTL == 600 }>10 minutes</option>
<option value="1800" selected?={ record.TTL == 1800 }>30 minutes</option>
<option value="3600" selected?={ record.TTL == 3600 }>1 hour</option>
<option value="7200" selected?={ record.TTL == 7200 }>2 hours</option>
<option value="18000" selected?={ record.TTL == 18000 }>5 hours</option>
<option value="43200" selected?={ record.TTL == 43200 }>12 hours</option>
<option value="86400" selected?={ record.TTL == 86400 }>1 day</option>
</select>
</div>
<div class="col-md-6 mb-3 d-flex align-items-end">
<div class="form-check bg-light p-3 rounded w-100">
<input
type="checkbox"
class="form-check-input"
id="record-proxied"
name="proxied"
checked?={ record.Proxied }
/>
<label class="form-check-label fw-semibold" for="record-proxied">
<i class="bi bi-shield-check text-success me-2"></i>
Proxied through Cloudflare
</label>
<div class="form-text">
Enable Cloudflare's proxy and security features
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
@click="$el.closest('dialog').close()"
>
<i class="bi bi-x-lg me-1"></i>
Cancel
</button>
<button
type="submit"
class="btn btn-primary"
:disabled="saving"
>
<template x-if="!saving">
<span class="d-flex align-items-center">
<i class="bi bi-check-lg me-2"></i>
if recordID != "" {
Update Record
} else {
Create Record
}
</span>
</template>
<template x-if="saving">
<span class="d-flex align-items-center">
<span class="spinner-border spinner-border-sm me-2"></span>
if recordID != "" {
Updating...
} else {
Creating...
}
</span>
</template>
</button>
</div>
</form>
</div>
</form>
<script>
function toggleMyIPOption() {
const recordType = document.getElementById('record-type').value;
const useMyIPGroup = document.getElementById('use-my-ip-group');
const contentGroup = document.getElementById('content-group');
if (recordType === 'A') {
useMyIPGroup.style.display = 'block';
} else {
useMyIPGroup.style.display = 'none';
contentGroup.style.display = 'block';
document.getElementById('use-my-ip').checked = false;
}
}
function toggleContentField() {
const useMyIP = document.getElementById('use-my-ip').checked;
const contentGroup = document.getElementById('content-group');
contentGroup.style.display = useMyIP ? 'none' : 'block';
}
function resetRecordForm() {
setTimeout(() => {
document.getElementById('record-type').value = 'A';
toggleMyIPOption();
}, 100);
}
// Initialize the form state
toggleMyIPOption();
</script>
</div>
}

View file

@ -31,46 +31,46 @@ func ConfigModal(config ConfigData, frequencies []UpdateFrequency) templ.Compone
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"modal fade\" id=\"configModal\" tabindex=\"-1\" aria-labelledby=\"configModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"configModalLabel\">Configuration</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><form hx-post=\"/config\" hx-target=\"body\" hx-swap=\"outerHTML\"><div class=\"modal-body\"><div class=\"mb-3\"><label for=\"api-token\" class=\"form-label\">Cloudflare API Token</label> <input type=\"password\" class=\"form-control\" id=\"api-token\" name=\"api_token\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div id=\"contact\" class=\"modal-container\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\">Configuration Settings</h5><button type=\"button\" class=\"btn-close\" @click=\"$el.closest('dialog').close()\" aria-label=\"Close\"></button></div><form x-target=\"config-status\" method=\"post\" action=\"/config\" @ajax:success=\"$el.closest('dialog').close()\" x-data=\"{ saving: false }\" @ajax:before=\"saving = true\" @ajax:after=\"saving = false\" @ajax:error=\"saving = false\"><div class=\"modal-body\"><div class=\"mb-3\"><label for=\"api-token\" class=\"form-label fw-semibold\"><i class=\"bi bi-key-fill text-primary me-2\"></i> Cloudflare API Token</label> <input type=\"password\" class=\"form-control\" id=\"api-token\" name=\"api_token\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(config.ApiToken)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 33, Col: 31}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 38, Col: 30}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" required><div class=\"form-text\">Create a token with <code>Zone.DNS:Edit</code> permissions in the Cloudflare dashboard.</div></div><div class=\"mb-3\"><label for=\"zone-id-input\" class=\"form-label\">Zone ID</label> <input type=\"text\" class=\"form-control\" id=\"zone-id-input\" name=\"zone_id\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" placeholder=\"Enter your Cloudflare API token\" required><div class=\"form-text\"><i class=\"bi bi-info-circle me-1\"></i> Create a token with <code>Zone.DNS:Edit</code> permissions in the Cloudflare dashboard.</div></div><div class=\"mb-3\"><label for=\"zone-id-input\" class=\"form-label fw-semibold\"><i class=\"bi bi-globe text-info me-2\"></i> Zone ID</label> <input type=\"text\" class=\"form-control\" id=\"zone-id-input\" name=\"zone_id\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(config.ZoneID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 48, Col: 29}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 58, Col: 28}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\" required><div class=\"form-text\">Found in the Cloudflare dashboard under your domain's overview page.</div></div><div class=\"mb-3\"><label for=\"domain-input\" class=\"form-label\">Domain</label> <input type=\"text\" class=\"form-control\" id=\"domain-input\" name=\"domain\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\" placeholder=\"e.g., 1234567890abcdef1234567890abcdef\" required><div class=\"form-text\"><i class=\"bi bi-info-circle me-1\"></i> Found in the Cloudflare dashboard under your domain's overview page.</div></div><div class=\"mb-3\"><label for=\"domain-input\" class=\"form-label fw-semibold\"><i class=\"bi bi-link-45deg text-success me-2\"></i> Domain</label> <input type=\"text\" class=\"form-control\" id=\"domain-input\" name=\"domain\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(config.Domain)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 62, Col: 29}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 77, Col: 28}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\" required></div><div class=\"mb-3\"><label for=\"update-period\" class=\"form-label\">Update Frequency</label> <select class=\"form-select\" id=\"update-period\" name=\"update_period\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\" placeholder=\"e.g., example.com\" required></div><div class=\"mb-3\"><label for=\"update-period\" class=\"form-label fw-semibold\"><i class=\"bi bi-clock text-warning me-2\"></i> Update Frequency</label> <select class=\"form-select\" id=\"update-period\" name=\"update_period\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -82,7 +82,7 @@ func ConfigModal(config ConfigData, frequencies []UpdateFrequency) templ.Compone
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(freq.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 70, Col: 35}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 89, Col: 34}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@ -105,7 +105,7 @@ func ConfigModal(config ConfigData, frequencies []UpdateFrequency) templ.Compone
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(freq.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 71, Col: 22}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 90, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@ -116,44 +116,7 @@ func ConfigModal(config ConfigData, frequencies []UpdateFrequency) templ.Compone
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</select></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"submit\" class=\"btn btn-primary\">Save <span class=\"htmx-indicator spinner-border spinner-border-sm ms-1\"></span></button></div></form></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func RecordModal(domain 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_Var7 := templ.GetChildren(ctx)
if templ_7745c5c3_Var7 == nil {
templ_7745c5c3_Var7 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"modal fade\" id=\"recordModal\" tabindex=\"-1\" aria-labelledby=\"recordModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog\"><div id=\"record-modal-content\" class=\"modal-content\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = RecordForm("Add DNS Record", "", domain, DNSRecord{Type: "A", TTL: 1}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div></div></div>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</select></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" @click=\"$el.closest('dialog').close()\"><i class=\"bi bi-x-lg me-1\"></i> Cancel</button> <button type=\"submit\" class=\"btn btn-primary\" :disabled=\"saving\"><template x-if=\"!saving\"><span class=\"d-flex align-items-center\"><i class=\"bi bi-check-lg me-2\"></i> Save Configuration</span></template><template x-if=\"saving\"><span class=\"d-flex align-items-center\"><span class=\"spinner-border spinner-border-sm me-2\"></span> Saving...</span></template></button></div></form></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -177,79 +140,105 @@ func RecordForm(title, recordID, domain string, record DNSRecord) templ.Componen
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
templ_7745c5c3_Var7 := templ.GetChildren(ctx)
if templ_7745c5c3_Var7 == nil {
templ_7745c5c3_Var7 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<div class=\"modal-header\"><h5 class=\"modal-title\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div id=\"contact\" class=\"modal-container\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\"><i class=\"bi bi-dns text-primary me-2\"></i> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(title)
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 114, Col: 33}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 135, Col: 12}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><form")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</h5><button type=\"button\" class=\"btn-close\" @click=\"$el.closest('dialog').close()\" aria-label=\"Close\"></button></div><div id=\"error-message\" class=\"alert alert-danger d-none mx-3 mt-3\" role=\"alert\"><i class=\"bi bi-exclamation-triangle-fill me-2\"></i> <span class=\"error-text\"></span></div><form")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if recordID != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, " hx-put=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, " method=\"put\" action=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("/records/%s", recordID))
var templ_7745c5c3_Var9 templ.SafeURL
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL(fmt.Sprintf("/records/%s", recordID)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 124, Col: 48}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 151, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, " hx-post=\"/records\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, " method=\"post\" action=\"/records\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " hx-target=\"#dns-records-table\" hx-on::after-request=\"if(event.detail.successful) bootstrap.Modal.getInstance(document.getElementById('recordModal')).hide()\"><div class=\"modal-body\"><div class=\"mb-3\"><label for=\"record-name\" class=\"form-label\">Name</label><div class=\"input-group\"><input type=\"text\" class=\"form-control\" id=\"record-name\" name=\"name\" placeholder=\"subdomain\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " x-target=\"dns-records-table\" x-target.error=\"none\" @ajax:success=\"$el.closest('dialog').close()\" x-data=\"{ saving: false }\" @ajax:before=\"saving = true\" @ajax:after=\"saving = false\" @ajax:error=\"saving = false\"><div class=\"modal-body\"><div class=\"row\"><div class=\"col-md-8 mb-3\"><label for=\"record-name\" class=\"form-label fw-semibold\"><i class=\"bi bi-tag text-info me-2\"></i> Record Name</label><div class=\"input-group\"><input type=\"text\" class=\"form-control\" id=\"record-name\" name=\"name\" placeholder=\"subdomain\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(getRecordName(record.Name, domain))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 178, Col: 51}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" required> <span class=\"input-group-text bg-light text-muted\">.")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(getRecordName(record.Name, domain))
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(domain)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 141, Col: 48}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 181, Col: 68}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "\" required> <span class=\"input-group-text\">.")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</span></div><div class=\"form-text\"><i class=\"bi bi-info-circle me-1\"></i> Use <code>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(domain)
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs("@")
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 144, Col: 45}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 185, Col: 23}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</span></div><div class=\"form-text\">Use @ for the root domain</div></div><div class=\"mb-3\"><label for=\"record-type\" class=\"form-label\">Type</label> <select class=\"form-select\" id=\"record-type\" name=\"type\" onchange=\"toggleMyIPOption()\"><option value=\"A\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</code> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs("for")
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 185, Col: 40}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, " the root domain</div></div><div class=\"col-md-4 mb-3\"><label for=\"record-type\" class=\"form-label fw-semibold\"><i class=\"bi bi-diagram-3 text-success me-2\"></i> Type</label> <select class=\"form-select\" id=\"record-type\" name=\"type\" onchange=\"toggleMyIPOption()\"><option value=\"A\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -259,7 +248,7 @@ func RecordForm(title, recordID, domain string, record DNSRecord) templ.Componen
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, ">A</option> <option value=\"AAAA\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, ">A (IPv4)</option> <option value=\"AAAA\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -269,7 +258,7 @@ func RecordForm(title, recordID, domain string, record DNSRecord) templ.Componen
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, ">AAAA</option> <option value=\"CNAME\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, ">AAAA (IPv6)</option> <option value=\"CNAME\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -299,20 +288,20 @@ func RecordForm(title, recordID, domain string, record DNSRecord) templ.Componen
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, ">MX</option></select></div><div class=\"mb-3\" id=\"content-group\"><label for=\"record-content\" class=\"form-label\">Content</label> <input type=\"text\" class=\"form-control\" id=\"record-content\" name=\"content\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, ">MX</option></select></div></div><div class=\"mb-3\" id=\"content-group\"><label for=\"record-content\" class=\"form-label fw-semibold\"><i class=\"bi bi-file-text text-warning me-2\"></i> Content</label> <input type=\"text\" class=\"form-control\" id=\"record-content\" name=\"content\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(record.Content)
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(record.Content)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 170, Col: 27}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/modal.templ`, Line: 217, Col: 29}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\" required></div><div class=\"mb-3 form-check\" id=\"use-my-ip-group\" style=\"display: none;\"><input type=\"checkbox\" class=\"form-check-input\" id=\"use-my-ip\" name=\"use_my_ip\" onchange=\"toggleContentField()\"> <label class=\"form-check-label\" for=\"use-my-ip\">Use my current IP address</label></div><div class=\"mb-3\"><label for=\"record-ttl\" class=\"form-label\">TTL</label> <select class=\"form-select\" id=\"record-ttl\" name=\"ttl\"><option value=\"1\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\" placeholder=\"Enter the record value\" required></div><div class=\"mb-3 form-check bg-light p-3 rounded\" id=\"use-my-ip-group\" style=\"display: none;\"><input type=\"checkbox\" class=\"form-check-input\" id=\"use-my-ip\" name=\"use_my_ip\" onchange=\"toggleContentField()\"> <label class=\"form-check-label fw-semibold\" for=\"use-my-ip\"><i class=\"bi bi-geo-alt text-primary me-2\"></i> Use my current IP address</label><div class=\"form-text\">Automatically use your current public IP address</div></div><div class=\"row\"><div class=\"col-md-6 mb-3\"><label for=\"record-ttl\" class=\"form-label fw-semibold\"><i class=\"bi bi-clock-history text-secondary me-2\"></i> TTL (Time to Live)</label> <select class=\"form-select\" id=\"record-ttl\" name=\"ttl\"><option value=\"1\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -412,7 +401,7 @@ func RecordForm(title, recordID, domain string, record DNSRecord) templ.Componen
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, ">1 day</option></select></div><div class=\"mb-3 form-check\"><input type=\"checkbox\" class=\"form-check-input\" id=\"record-proxied\" name=\"proxied\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, ">1 day</option></select></div><div class=\"col-md-6 mb-3 d-flex align-items-end\"><div class=\"form-check bg-light p-3 rounded w-100\"><input type=\"checkbox\" class=\"form-check-input\" id=\"record-proxied\" name=\"proxied\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -422,7 +411,37 @@ func RecordForm(title, recordID, domain string, record DNSRecord) templ.Componen
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "> <label class=\"form-check-label\" for=\"record-proxied\">Proxied through Cloudflare</label></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"submit\" class=\"btn btn-primary\">Save <span class=\"htmx-indicator spinner-border spinner-border-sm ms-1\"></span></button></div></form><script>\n\t\tfunction toggleMyIPOption() {\n\t\t\tconst recordType = document.getElementById('record-type').value;\n\t\t\tconst useMyIPGroup = document.getElementById('use-my-ip-group');\n\t\t\tconst contentGroup = document.getElementById('content-group');\n\n\t\t\tif (recordType === 'A') {\n\t\t\t\tuseMyIPGroup.style.display = 'block';\n\t\t\t} else {\n\t\t\t\tuseMyIPGroup.style.display = 'none';\n\t\t\t\tcontentGroup.style.display = 'block';\n\t\t\t\tdocument.getElementById('use-my-ip').checked = false;\n\t\t\t}\n\t\t}\n\n\t\tfunction toggleContentField() {\n\t\t\tconst useMyIP = document.getElementById('use-my-ip').checked;\n\t\t\tconst contentGroup = document.getElementById('content-group');\n\t\t\tcontentGroup.style.display = useMyIP ? 'none' : 'block';\n\t\t}\n\n\t\tfunction resetRecordForm() {\n\t\t\tsetTimeout(() => {\n\t\t\t\tdocument.getElementById('record-type').value = 'A';\n\t\t\t\ttoggleMyIPOption();\n\t\t\t}, 100);\n\t\t}\n\n\t\t// Initialize the form state\n\t\ttoggleMyIPOption();\n\t</script>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "> <label class=\"form-check-label fw-semibold\" for=\"record-proxied\"><i class=\"bi bi-shield-check text-success me-2\"></i> Proxied through Cloudflare</label><div class=\"form-text\">Enable Cloudflare's proxy and security features</div></div></div></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" @click=\"$el.closest('dialog').close()\"><i class=\"bi bi-x-lg me-1\"></i> Cancel</button> <button type=\"submit\" class=\"btn btn-primary\" :disabled=\"saving\"><template x-if=\"!saving\"><span class=\"d-flex align-items-center\"><i class=\"bi bi-check-lg me-2\"></i> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if recordID != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "Update Record")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "Create Record")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "</span></template><template x-if=\"saving\"><span class=\"d-flex align-items-center\"><span class=\"spinner-border spinner-border-sm me-2\"></span> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if recordID != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "Updating...")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "Creating...")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</span></template></button></div></form></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

73
templates/toast.templ Normal file
View file

@ -0,0 +1,73 @@
package templates
import "fmt"
// NotificationList renders the container for notifications
templ NotificationList() {
<ul x-sync id="notification_list" x-merge="prepend" role="status" class="list-unstyled">
{ children... }
</ul>
}
// NotificationToast renders a single notification toast
templ NotificationToast(message, notificationType string) {
<li>
<div
class={ fmt.Sprintf("toast align-items-center text-white bg-%s show", notificationType) }
role="alert"
aria-live="assertive"
aria-atomic="true"
x-data="{
show: false,
init() {
this.$nextTick(() => this.show = true);
setTimeout(() => this.dismiss(), 6000);
},
dismiss() {
this.show = false;
setTimeout(() => this.$root.remove(), 500);
}
}"
x-show="show"
x-transition.duration.500ms
>
<div class="d-flex">
<div class="toast-body">{ message }</div>
<button
type="button"
class="btn-close btn-close-white me-2 m-auto"
@click="dismiss()"
aria-label="Close"
>
&times;
</button>
</div>
</div>
</li>
}
// Helper functions for common notification types
templ SuccessNotification(message string) {
@NotificationList() {
@NotificationToast(message, "success")
}
}
templ ErrorNotification(message string) {
@NotificationList() {
@NotificationToast(message, "danger")
}
}
templ WarningNotification(message string) {
@NotificationList() {
@NotificationToast(message, "warning")
}
}
templ InfoNotification(message string) {
@NotificationList() {
@NotificationToast(message, "info")
}
}

306
templates/toast_templ.go Normal file
View file

@ -0,0 +1,306 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.898
package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import "fmt"
// NotificationList renders the container for notifications
func NotificationList() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<ul x-sync id=\"notification_list\" x-merge=\"prepend\" role=\"status\" class=\"list-unstyled\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</ul>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// NotificationToast renders a single notification toast
func NotificationToast(message, notificationType 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_Var2 := templ.GetChildren(ctx)
if templ_7745c5c3_Var2 == nil {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 = []any{fmt.Sprintf("toast align-items-center text-white bg-%s show", notificationType)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var3).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/toast.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\" role=\"alert\" aria-live=\"assertive\" aria-atomic=\"true\" x-data=\"{\n\t\t\t\tshow: false,\n\t\t\t\tinit() {\n\t\t\t\t\tthis.$nextTick(() => this.show = true);\n\t\t\t\t\tsetTimeout(() => this.dismiss(), 6000);\n\t\t\t\t},\n\t\t\t\tdismiss() {\n\t\t\t\t\tthis.show = false;\n\t\t\t\t\tsetTimeout(() => this.$root.remove(), 500);\n\t\t\t\t}\n\t\t\t}\" x-show=\"show\" x-transition.duration.500ms><div class=\"d-flex\"><div class=\"toast-body\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/toast.templ`, Line: 36, Col: 37}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</div><button type=\"button\" class=\"btn-close btn-close-white me-2 m-auto\" @click=\"dismiss()\" aria-label=\"Close\">&times;</button></div></div></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// Helper functions for common notification types
func SuccessNotification(message 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_Var6 := templ.GetChildren(ctx)
if templ_7745c5c3_Var6 == nil {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var7 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = NotificationToast(message, "success").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = NotificationList().Render(templ.WithChildren(ctx, templ_7745c5c3_Var7), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func ErrorNotification(message 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_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var9 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = NotificationToast(message, "danger").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = NotificationList().Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func WarningNotification(message 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_Var10 := templ.GetChildren(ctx)
if templ_7745c5c3_Var10 == nil {
templ_7745c5c3_Var10 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var11 := 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 = NotificationToast(message, "warning").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = NotificationList().Render(templ.WithChildren(ctx, templ_7745c5c3_Var11), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func InfoNotification(message 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_Var12 := templ.GetChildren(ctx)
if templ_7745c5c3_Var12 == nil {
templ_7745c5c3_Var12 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var13 := 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 = NotificationToast(message, "info").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
templ_7745c5c3_Err = NotificationList().Render(templ.WithChildren(ctx, templ_7745c5c3_Var13), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate