devices: enhanced more displays
This commit is contained in:
parent
1dc3617df3
commit
3c8a1b1fd6
18
api/devices_exist.go
Normal file
18
api/devices_exist.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/tigorlazuardi/redmage/models"
|
||||
"github.com/tigorlazuardi/redmage/pkg/errs"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (api *API) DevicesExist(ctx context.Context, slug string) (exist bool, err error) {
|
||||
ctx, span := tracer.Start(ctx, "API.DevicesExist")
|
||||
defer span.End()
|
||||
|
||||
exist, err = models.Devices.Query(ctx, api.db, models.SelectWhere.Devices.Slug.EQ(slug)).Exists()
|
||||
if err != nil {
|
||||
return false, errs.Wrapw(err, "failed to check device existence", "slug", slug)
|
||||
}
|
||||
return exist, nil
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aarondl/opt/omit"
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
"github.com/tigorlazuardi/redmage/models"
|
||||
"github.com/tigorlazuardi/redmage/pkg/errs"
|
||||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
"github.com/tigorlazuardi/redmage/views/components"
|
||||
)
|
||||
|
||||
type deviceUpdate struct {
|
||||
|
@ -53,6 +55,7 @@ func (routes *Routes) APIDeviceUpdate(rw http.ResponseWriter, r *http.Request) {
|
|||
|
||||
device, err := routes.API.DevicesUpdate(ctx, slug, &models.DeviceSetter{
|
||||
Name: omit.FromCond(body.Name, body.Name != ""),
|
||||
Enable: omit.FromCond(body.Enable, body.Enable == 1 || body.Enable == 0),
|
||||
ResolutionX: omit.FromCond(body.ResolutionX, body.ResolutionX != 0),
|
||||
ResolutionY: omit.FromCond(body.ResolutionY, body.ResolutionY != 0),
|
||||
AspectRatioTolerance: omit.FromPtr(body.AspectRatioTolerance),
|
||||
|
@ -61,7 +64,6 @@ func (routes *Routes) APIDeviceUpdate(rw http.ResponseWriter, r *http.Request) {
|
|||
MaxX: omit.FromPtr(body.MaxX),
|
||||
MaxY: omit.FromPtr(body.MaxY),
|
||||
NSFW: omit.FromPtr(body.NSFW),
|
||||
WindowsWallpaperMode: omit.FromPtr(body.WindowsWallpaperMode),
|
||||
UpdatedAt: omit.From(time.Now().Unix()),
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -74,3 +76,106 @@ func (routes *Routes) APIDeviceUpdate(rw http.ResponseWriter, r *http.Request) {
|
|||
|
||||
_ = enc.Encode(device)
|
||||
}
|
||||
|
||||
func (routes *Routes) DevicesUpdateHTMX(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, span := tracer.Start(req.Context(), "*Routes.DevicesUpdateHTMX")
|
||||
defer span.End()
|
||||
|
||||
slug := chi.URLParam(req, "slug")
|
||||
exist, err := routes.API.DevicesExist(ctx, slug)
|
||||
if err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to check device slug existence")
|
||||
code, message := errs.HTTPMessage(err)
|
||||
rw.WriteHeader(code)
|
||||
if err := components.ErrorToast(message).Render(ctx, rw); err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to render error notification")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !exist {
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
if err := components.ErrorToast("Device with slug identifier '%s' does not exist", slug).Render(ctx, rw); err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to render error notification")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
device, err := routes.API.DevicesUpdate(ctx, slug, deviceSetterFromRequest(req))
|
||||
if err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to update device")
|
||||
code, message := errs.HTTPMessage(err)
|
||||
rw.WriteHeader(code)
|
||||
if err := components.ErrorToast(message).Render(ctx, rw); err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to render error notification")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set("HX-Redirect", fmt.Sprintf("/devices/details/%s", slug))
|
||||
if err := components.SuccessToast("Device %q has been updated", device.Name).Render(ctx, rw); err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to render success notification")
|
||||
}
|
||||
}
|
||||
|
||||
func deviceSetterFromRequest(req *http.Request) *models.DeviceSetter {
|
||||
setter := &models.DeviceSetter{
|
||||
UpdatedAt: omit.From(time.Now().Unix()),
|
||||
}
|
||||
|
||||
name := req.FormValue("name")
|
||||
setter.Name = omit.FromCond(name, name != "")
|
||||
|
||||
enable, err := strconv.Atoi(req.FormValue("enable"))
|
||||
if err == nil {
|
||||
if enable > 1 {
|
||||
enable = 1
|
||||
} else if enable < 0 {
|
||||
enable = 0
|
||||
}
|
||||
setter.Enable = omit.From(int32(enable))
|
||||
}
|
||||
|
||||
resx, _ := strconv.Atoi(req.FormValue("resolution_x"))
|
||||
setter.ResolutionX = omit.FromCond(float64(resx), resx != 0)
|
||||
|
||||
resy, _ := strconv.Atoi(req.FormValue("resolution_y"))
|
||||
setter.ResolutionY = omit.FromCond(float64(resy), resy != 0)
|
||||
|
||||
art, err := strconv.ParseFloat(req.FormValue("aspect_ratio_tolerance"), 64)
|
||||
if err == nil {
|
||||
setter.AspectRatioTolerance = omit.FromCond(art, art >= 0)
|
||||
}
|
||||
|
||||
minX, err := strconv.Atoi(req.FormValue("min_x"))
|
||||
if err == nil {
|
||||
setter.MinX = omit.FromCond(int32(minX), minX >= 0)
|
||||
}
|
||||
|
||||
minY, err := strconv.Atoi(req.FormValue("min_y"))
|
||||
if err == nil {
|
||||
setter.MinY = omit.FromCond(int32(minY), minY >= 0)
|
||||
}
|
||||
|
||||
maxX, err := strconv.Atoi(req.FormValue("max_x"))
|
||||
if err == nil {
|
||||
setter.MaxX = omit.FromCond(int32(maxX), maxX >= 0)
|
||||
}
|
||||
|
||||
maxY, err := strconv.Atoi(req.FormValue("max_y"))
|
||||
if err == nil {
|
||||
setter.MaxY = omit.FromCond(int32(maxY), maxY >= 0)
|
||||
}
|
||||
|
||||
nsfw, err := strconv.Atoi(req.FormValue("nsfw"))
|
||||
if err == nil {
|
||||
if nsfw > 1 {
|
||||
nsfw = 1
|
||||
} else if nsfw < 0 {
|
||||
nsfw = 0
|
||||
}
|
||||
setter.NSFW = omit.From(int32(nsfw))
|
||||
}
|
||||
|
||||
return setter
|
||||
}
|
||||
|
|
81
server/routes/page_devices_edit.go
Normal file
81
server/routes/page_devices_edit.go
Normal file
|
@ -0,0 +1,81 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/tigorlazuardi/redmage/pkg/errs"
|
||||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
"github.com/tigorlazuardi/redmage/views"
|
||||
"github.com/tigorlazuardi/redmage/views/components"
|
||||
"github.com/tigorlazuardi/redmage/views/devices/put"
|
||||
)
|
||||
|
||||
func (routes *Routes) PageDevicesEdit(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx, span := tracer.Start(req.Context(), "*Routes.PageDevicesEdit")
|
||||
defer span.End()
|
||||
|
||||
c := views.NewContext(routes.Config, req)
|
||||
|
||||
slug := chi.URLParam(req, "slug")
|
||||
|
||||
device, err := routes.API.DeviceBySlug(ctx, slug)
|
||||
if err != nil {
|
||||
code, message := errs.HTTPMessage(err)
|
||||
if code >= 500 {
|
||||
log.New(ctx).Err(err).Error("failed to get device by slug")
|
||||
}
|
||||
rw.WriteHeader(code)
|
||||
msg := fmt.Sprintf("%d: %s", code, message)
|
||||
if err := components.PageError(c, msg).Render(ctx, rw); err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to render device edit page")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
data := put.Data{
|
||||
PageTitle: fmt.Sprintf("Edit Device %q", device.Name),
|
||||
PostAction: fmt.Sprintf("/devices/edit/%s", device.Slug),
|
||||
EditMode: true,
|
||||
NameInput: put.NameInputData{
|
||||
Value: device.Name,
|
||||
EditMode: true,
|
||||
},
|
||||
SlugInput: put.SlugInputData{
|
||||
Value: device.Slug,
|
||||
},
|
||||
ResolutionX: put.ResolutionData{
|
||||
Value: int(device.ResolutionX),
|
||||
},
|
||||
ResolutionY: put.ResolutionData{
|
||||
Value: int(device.ResolutionY),
|
||||
},
|
||||
AspectRatioTolerance: put.AspectRatioToleranceData{
|
||||
Value: device.AspectRatioTolerance,
|
||||
},
|
||||
NSFWCheckbox: put.NSFWCheckboxData{
|
||||
Checked: device.NSFW == 1,
|
||||
EditMode: true,
|
||||
},
|
||||
WindowsWallpaperCheckbox: put.WindowsWallpaperCheckboxData{
|
||||
Checked: device.WindowsWallpaperMode == 1,
|
||||
},
|
||||
MinImageResolutionXInput: put.ResolutionData{
|
||||
Value: int(device.MinX),
|
||||
},
|
||||
MinImageResolutionYInput: put.ResolutionData{
|
||||
Value: int(device.MinY),
|
||||
},
|
||||
MaxImageResolutionXInput: put.ResolutionData{
|
||||
Value: int(device.MaxX),
|
||||
},
|
||||
MaxImageResolutionYInput: put.ResolutionData{
|
||||
Value: int(device.MaxY),
|
||||
},
|
||||
}
|
||||
|
||||
if err := put.View(c, data).Render(ctx, rw); err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to render device edit page")
|
||||
}
|
||||
}
|
|
@ -88,6 +88,8 @@ func (routes *Routes) registerWWWRoutes(router chi.Router) {
|
|||
r.Get("/devices/add", routes.PageDevicesAdd)
|
||||
r.Post("/devices/add", routes.DevicesCreateHTMX)
|
||||
r.Get("/devices/details/{slug}", routes.PageDeviceDetails)
|
||||
r.Get("/devices/edit/{slug}", routes.PageDevicesEdit)
|
||||
r.Post("/devices/edit/{slug}", routes.DevicesUpdateHTMX)
|
||||
r.Get("/schedules", routes.PageScheduleHistory)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package components
|
|||
|
||||
import "github.com/tigorlazuardi/redmage/models"
|
||||
import "fmt"
|
||||
import "github.com/tigorlazuardi/redmage/views/utils"
|
||||
import "time"
|
||||
|
||||
type ImageCardOption uint
|
||||
|
||||
|
@ -26,7 +26,18 @@ const (
|
|||
)
|
||||
|
||||
templ ImageCard(data *models.Image, opts ImageCardOption) {
|
||||
<div class="not-prose card card-bordered bg-base-100 hover:bg-base-200 shadow-xl min-w-[16rem] max-w-[16rem] rounded-xl top-0 hover:-top-1 hover:drop-shadow-2xl transition-all">
|
||||
<div
|
||||
x-data={ fmt.Sprintf(`{
|
||||
time: %d,
|
||||
get timeTooltip() {
|
||||
return dayjs.unix(this.time).tz(dayjs.tz.guess()).format('ddd, D MMM YYYY HH:mm:ss Z')
|
||||
},
|
||||
get relativeTime() {
|
||||
return dayjs.unix(this.time).tz(dayjs.tz.guess()).fromNow()
|
||||
},
|
||||
}`, data.CreatedAt) }
|
||||
class="not-prose card card-bordered bg-base-100 hover:bg-base-200 shadow-xl min-w-[16rem] max-w-[16rem] rounded-xl top-0 hover:-top-1 hover:drop-shadow-2xl transition-all"
|
||||
>
|
||||
<figure>
|
||||
<a
|
||||
href={ templ.URL(fmt.Sprintf("/img/%s", data.ImageRelativePath)) }
|
||||
|
@ -51,7 +62,9 @@ templ ImageCard(data *models.Image, opts ImageCardOption) {
|
|||
<a class="text-primary text-sm underline" href={ templ.URL(data.PostAuthorURL) }>{ data.PostAuthor }</a>
|
||||
<div class="flex-1"></div>
|
||||
<div class="flex">
|
||||
@utils.RelativeTimeNode(fmt.Sprintf("relative-time-%s", data.PostName), data.CreatedAt, "text-sm")
|
||||
<div class="tooltip" :data-tip="timeTooltip">
|
||||
<span class="text-xs" :class="{ 'text-xs': false }" x-text="relativeTime">{ time.Unix(data.CreatedAt, 0).Format("Mon, _2 Jan 2006 15:04:05 MST") } </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2">
|
||||
<p class="text-xs">{ fmt.Sprintf("%d \u00d7 %d", data.ImageWidth, data.ImageHeight) } px</p>
|
||||
|
|
|
@ -2,7 +2,7 @@ package components
|
|||
|
||||
import "github.com/tigorlazuardi/redmage/views"
|
||||
|
||||
templ Page404(c *views.Context, text string) {
|
||||
templ PageError(c *views.Context, text string) {
|
||||
@Doctype() {
|
||||
@Head(c, HeadTitle(text))
|
||||
@Body(c) {
|
|
@ -1,8 +1,9 @@
|
|||
package details
|
||||
|
||||
import "fmt"
|
||||
import "github.com/tigorlazuardi/redmage/views"
|
||||
|
||||
templ filter(data Data) {
|
||||
templ filter(c *views.Context, data Data) {
|
||||
<div
|
||||
id="filter-bar"
|
||||
hx-get={ fmt.Sprintf("/devices/details/%s", data.Device.Slug) }
|
||||
|
@ -12,9 +13,9 @@ templ filter(data Data) {
|
|||
hx-select="main"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
class="grid sm:grid-cols-2 md:grid-cols-4 gap-4"
|
||||
class="grid md:grid-cols-2 gap-4 items-center"
|
||||
>
|
||||
<label class="input input-bordered flex items-center gap-2 sm:col-span-2 md:col-auto">
|
||||
<label class="input input-bordered flex items-center gap-2">
|
||||
<input
|
||||
id="search"
|
||||
type="text"
|
||||
|
@ -31,5 +32,32 @@ templ filter(data Data) {
|
|||
class="w-4 h-4 opacity-70"
|
||||
><path fill-rule="evenodd" d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z" clip-rule="evenodd"></path></svg>
|
||||
</label>
|
||||
<div class="grid grid-cols-[1fr,3fr] sm:grid-cols-[1fr,3fr,1fr,3fr] gap-4 items-center">
|
||||
<label for="limit">Limit</label>
|
||||
<select id="limit" name="limit" class="select select-bordered w-full">
|
||||
<option value="25" selected?={ data.Params.Limit == 25 }>25</option>
|
||||
<option value="50" selected?={ data.Params.Limit == 50 }>50</option>
|
||||
<option value="75" selected?={ data.Params.Limit == 75 }>75</option>
|
||||
<option value="100" selected?={ data.Params.Limit == 100 }>100</option>
|
||||
</select>
|
||||
<label for="range">Range</label>
|
||||
<select id="range" name="created_at" class="select select-bordered w-full">
|
||||
@rangeOption(c, "-10800", "3 Hours")
|
||||
@rangeOption(c, "-21600", "6 Hours")
|
||||
@rangeOption(c, "-43200", "12 Hours")
|
||||
<option
|
||||
value="-86400"
|
||||
selected?={ c.Request.URL.Query().Get("created_at") == "" || c.Request.URL.Query().Get("created_at") == "-86400" }
|
||||
>1 Day</option>
|
||||
@rangeOption(c, "-172800", "2 Days")
|
||||
@rangeOption(c, "-259200", "3 Days")
|
||||
@rangeOption(c, "-604800", "7 Days")
|
||||
@rangeOption(c, "-2592000", "30 Days")
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ rangeOption(c *views.Context, value, display string) {
|
||||
<option value={ value } selected?={ c.Request.URL.Query().Get("created_at") == value }>{ display }</option>
|
||||
}
|
||||
|
|
|
@ -24,9 +24,15 @@ templ Content(c *views.Context, data Data) {
|
|||
if data.Error != "" {
|
||||
@components.ErrorToast(data.Error)
|
||||
} else {
|
||||
<h1>{ data.Device.Name }</h1>
|
||||
<div class="flex justify-between items-center">
|
||||
<h1 class="my-auto">{ data.Device.Name }</h1>
|
||||
<a
|
||||
href={ templ.SafeURL(fmt.Sprintf("/devices/edit/%s", data.Device.Slug)) }
|
||||
class="btn btn-primary no-underline sm:w-24"
|
||||
>Edit</a>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
@filter(data)
|
||||
@filter(c, data)
|
||||
for _, group := range data.splitImages() {
|
||||
<h2>{ group.Subreddit }</h2>
|
||||
@imageList(group.Images)
|
||||
|
|
|
@ -69,7 +69,7 @@ templ MaxImageResolutionYInput(data ResolutionData) {
|
|||
<input
|
||||
id="max-image-height-field"
|
||||
x-data={ fmt.Sprintf(`{ init() { $el.setCustomValidity(%q) } }`, data.Error) }
|
||||
name="min_y"
|
||||
name="max_y"
|
||||
type="number"
|
||||
min="0"
|
||||
@change="$el.setCustomValidity(''); this.error = false"
|
||||
|
|
|
@ -4,13 +4,13 @@ import "github.com/tigorlazuardi/redmage/views/utils"
|
|||
import "fmt"
|
||||
|
||||
type NameInputData struct {
|
||||
Error string
|
||||
Value string
|
||||
DisableValidation bool
|
||||
Error string
|
||||
Value string
|
||||
EditMode bool
|
||||
}
|
||||
|
||||
templ NameInput(data NameInputData) {
|
||||
<label id="name-input-form" class="form-control">
|
||||
<label id="name-input-form" class={ utils.CXX("form-control", true, "col-span-2", data.EditMode) }>
|
||||
<div class="label">
|
||||
<span
|
||||
class={ utils.CXX("label-text", true, "text-error", data.Error != "") }
|
||||
|
@ -18,7 +18,7 @@ templ NameInput(data NameInputData) {
|
|||
</div>
|
||||
<input
|
||||
id="name-input-field"
|
||||
if !data.DisableValidation {
|
||||
if !data.EditMode {
|
||||
required
|
||||
x-data={ fmt.Sprintf(`{ init() { $el.setCustomValidity(%q) } }`, data.Error) }
|
||||
hx-get="/htmx/devices/add/validate/name"
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
package put
|
||||
|
||||
import "fmt"
|
||||
import "github.com/tigorlazuardi/redmage/views/utils"
|
||||
|
||||
type NSFWCheckboxData struct {
|
||||
Checked bool
|
||||
Checked bool
|
||||
EditMode bool
|
||||
}
|
||||
|
||||
templ NSFWCheckbox(data NSFWCheckboxData) {
|
||||
<div
|
||||
x-data={ fmt.Sprintf(`{checked: %t}`, data.Checked) }
|
||||
class="form-control"
|
||||
class={ utils.CXX("form-control", true, "col-span-2", data.EditMode) }
|
||||
>
|
||||
<label
|
||||
class="label cursor-pointer border input input-bordered"
|
||||
|
|
|
@ -4,12 +4,10 @@ import "github.com/tigorlazuardi/redmage/views/utils"
|
|||
import "fmt"
|
||||
|
||||
type SlugInputData struct {
|
||||
Error string
|
||||
Value string
|
||||
Valid string
|
||||
HXSwapOOB bool
|
||||
Disabled bool
|
||||
DisabledText string
|
||||
Error string
|
||||
Value string
|
||||
Valid string
|
||||
HXSwapOOB bool
|
||||
}
|
||||
|
||||
templ SlugInput(data SlugInputData) {
|
||||
|
@ -28,17 +26,14 @@ templ SlugInput(data SlugInputData) {
|
|||
"text-success", data.Valid != "",
|
||||
) }
|
||||
>Slug Identifier</span>
|
||||
<span class="label-text-alt italic font-bold text-primary">NOTE: Slug Identifier cannot be changed after creation</span>
|
||||
</div>
|
||||
<input
|
||||
id="slug-input-field"
|
||||
if !data.Disabled {
|
||||
x-data={ fmt.Sprintf(`{ init() { $el.setCustomValidity(%q) } }`, data.Error) }
|
||||
}
|
||||
x-data={ fmt.Sprintf(`{ init() { $el.setCustomValidity(%q) } }`, data.Error) }
|
||||
name="slug"
|
||||
type="text"
|
||||
if !data.Disabled {
|
||||
@change="$el.setCustomValidity('')"
|
||||
}
|
||||
@change="$el.setCustomValidity('')"
|
||||
class={ utils.CXX(
|
||||
"input input-bordered", true,
|
||||
"text-error", data.Error != "",
|
||||
|
@ -46,18 +41,14 @@ templ SlugInput(data SlugInputData) {
|
|||
"input-error", data.Error != "",
|
||||
"input-success", data.Valid != "",
|
||||
) }
|
||||
if data.Disabled {
|
||||
disabled
|
||||
} else {
|
||||
hx-get="/htmx/devices/add/validate/slug"
|
||||
hx-trigger="change, input delay:2s"
|
||||
hx-target="#slug-input-form"
|
||||
hx-target-error="#slug-input-form"
|
||||
hx-swap="outerHTML"
|
||||
placeholder="my-awesome-device"
|
||||
title="Url Friendly Characters Only"
|
||||
required
|
||||
}
|
||||
hx-get="/htmx/devices/add/validate/slug"
|
||||
hx-trigger="change, input delay:2s"
|
||||
hx-target="#slug-input-form"
|
||||
hx-target-error="#slug-input-form"
|
||||
hx-swap="outerHTML"
|
||||
placeholder="my-awesome-device"
|
||||
title="Url Friendly Characters Only"
|
||||
required
|
||||
value={ data.Value }
|
||||
/>
|
||||
<div class="label">
|
||||
|
@ -66,8 +57,6 @@ templ SlugInput(data SlugInputData) {
|
|||
{ data.Valid }
|
||||
} else if data.Error != "" {
|
||||
{ data.Error }
|
||||
} else if data.DisabledText != "" {
|
||||
{ data.DisabledText }
|
||||
} else {
|
||||
URL friendly Unique identifier for the device.
|
||||
Value must be lowercase english alphabet and supported separator is only 'dash' (-) and 'underscores' (_).
|
||||
|
|
|
@ -6,6 +6,7 @@ import "github.com/tigorlazuardi/redmage/views/components"
|
|||
type Data struct {
|
||||
PageTitle string
|
||||
PostAction string
|
||||
EditMode bool
|
||||
|
||||
NameInput NameInputData
|
||||
SlugInput SlugInputData
|
||||
|
@ -38,24 +39,28 @@ templ Content(c *views.Context, data Data) {
|
|||
method="post"
|
||||
hx-post={ data.PostAction }
|
||||
action={ templ.SafeURL(data.PostAction) }
|
||||
class="grid sm:grid-cols-2 gap-4"
|
||||
class="grid sm:grid-cols-2 gap-4 sm:gap-y-8"
|
||||
hx-target={ components.NotificationContainerID }
|
||||
hx-target-error={ components.NotificationContainerID }
|
||||
hx-swap="afterbegin"
|
||||
>
|
||||
@NameInput(data.NameInput)
|
||||
@SlugInput(data.SlugInput)
|
||||
if !data.EditMode {
|
||||
@SlugInput(data.SlugInput)
|
||||
}
|
||||
@ResolutionXInput(data.ResolutionX)
|
||||
@ResolutionYInput(data.ResolutionY)
|
||||
<div class="divider my-auto sm:col-span-2"><h3 class="m-0 p-0">Filter</h3></div>
|
||||
<div class="divider my-auto sm:col-span-2 sm:my-8"><h3 class="m-0 p-0">Filter</h3></div>
|
||||
@AspectRatioToleranceInput(data.AspectRatioTolerance)
|
||||
@NSFWCheckbox(data.NSFWCheckbox)
|
||||
@WindowsWallpaperCheckbox(data.WindowsWallpaperCheckbox)
|
||||
if !data.EditMode {
|
||||
@WindowsWallpaperCheckbox(data.WindowsWallpaperCheckbox)
|
||||
}
|
||||
@MinImageResolutionXInput(data.MinImageResolutionXInput)
|
||||
@MinImageResolutionYInput(data.MinImageResolutionYInput)
|
||||
@MaxImageResolutionXInput(data.MaxImageResolutionXInput)
|
||||
@MaxImageResolutionYInput(data.MaxImageResolutionYInput)
|
||||
<button type="submit" class="btn btn-primary sm:col-span-2">Add</button>
|
||||
<button type="submit" class="btn btn-primary sm:col-span-2">Save</button>
|
||||
</form>
|
||||
}
|
||||
</main>
|
||||
|
|
|
@ -35,6 +35,7 @@ templ WindowsWallpaperCheckbox(data WindowsWallpaperCheckboxData) {
|
|||
>
|
||||
Windows Wallpaper Mode puts images for this device under one folder instead of split by subreddits.
|
||||
This allows the user to target Windows Wallpaper to the whole image collections.
|
||||
<span class="text-primary italic font-bold">Windows wallpaper mode cannot be changed after creation.</span>
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -36,7 +36,9 @@ templ DetailsContent(c *views.Context, data Data) {
|
|||
if data.Error != "" {
|
||||
<h1>Error: { data.Error }</h1>
|
||||
} else {
|
||||
<h1>Subreddit { data.Subreddit.Name }</h1>
|
||||
<div class="flex items-center justify-between">
|
||||
<h1>Subreddit { data.Subreddit.Name }</h1>
|
||||
</div>
|
||||
<div class="flex flex-wrap justify-between content-center">
|
||||
<h2 class="my-auto">
|
||||
Total Images:
|
||||
|
|
Loading…
Reference in a new issue