view(subreddits-list): added filter bar
This commit is contained in:
parent
d2b81567e3
commit
4f3ba41237
|
@ -20,6 +20,7 @@ type ListSubredditsParams struct {
|
|||
Offset int64
|
||||
OrderBy string
|
||||
Sort string
|
||||
NSFW int
|
||||
}
|
||||
|
||||
func (l *ListSubredditsParams) FillFromQuery(q Queryable) {
|
||||
|
@ -37,6 +38,11 @@ func (l *ListSubredditsParams) FillFromQuery(q Queryable) {
|
|||
}
|
||||
l.OrderBy = q.Get("order_by")
|
||||
l.Sort = strings.ToLower(q.Get("sort"))
|
||||
if nsfw, err := strconv.Atoi(q.Get("nsfw")); err == nil {
|
||||
l.NSFW = nsfw
|
||||
} else {
|
||||
l.NSFW = -1
|
||||
}
|
||||
}
|
||||
|
||||
func (l ListSubredditsParams) Query() (expr []bob.Mod[*dialect.SelectQuery]) {
|
||||
|
@ -56,12 +62,23 @@ func (l ListSubredditsParams) Query() (expr []bob.Mod[*dialect.SelectQuery]) {
|
|||
expr = append(expr, sm.OrderBy(sqlite.Quote(l.OrderBy)).Asc())
|
||||
}
|
||||
} else {
|
||||
expr = append(expr, sm.OrderBy(models.SubredditColumns.Name).Asc())
|
||||
expr = append(expr, sm.OrderBy(models.SubredditColumns.UpdatedAt).Desc())
|
||||
}
|
||||
|
||||
return expr
|
||||
}
|
||||
|
||||
func (l ListSubredditsParams) ImageCoverQuery(subname string) (expr []bob.Mod[*dialect.SelectQuery]) {
|
||||
expr = make([]bob.Mod[*dialect.SelectQuery], 0, 4)
|
||||
expr = append(expr, models.SelectWhere.Images.Subreddit.EQ(subname))
|
||||
if l.NSFW >= 0 {
|
||||
expr = append(expr, models.SelectWhere.Images.NSFW.EQ(int32(l.NSFW)))
|
||||
}
|
||||
expr = append(expr, sm.Limit(1))
|
||||
expr = append(expr, sm.OrderBy(models.ImageColumns.CreatedAt).Desc())
|
||||
return expr
|
||||
}
|
||||
|
||||
func (l ListSubredditsParams) CountQuery() (expr []bob.Mod[*dialect.SelectQuery]) {
|
||||
if l.Q != "" {
|
||||
expr = append(expr, models.SelectWhere.Subreddits.Name.Like("%"+l.Q+"%"))
|
||||
|
@ -112,11 +129,7 @@ func (api *API) ListSubredditsWithCover(ctx context.Context, arg ListSubredditsP
|
|||
//
|
||||
// Subreddit list is expected to be small, so this should be fine since SQLITE has no network latency.
|
||||
for _, subreddit := range result.Data {
|
||||
subreddit.R.Images, err = models.Images.Query(ctx, api.db,
|
||||
models.SelectWhere.Images.Subreddit.EQ(subreddit.Name),
|
||||
sm.Limit(1),
|
||||
sm.OrderBy(models.ImageColumns.CreatedAt).Desc(),
|
||||
).All()
|
||||
subreddit.R.Images, err = models.Images.Query(ctx, api.db, arg.ImageCoverQuery(subreddit.Name)...).All()
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
|
|
@ -3,7 +3,6 @@ package routes
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/tigorlazuardi/redmage/api"
|
||||
"github.com/tigorlazuardi/redmage/pkg/errs"
|
||||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
"github.com/tigorlazuardi/redmage/views"
|
||||
|
@ -15,14 +14,11 @@ func (routes *Routes) PageSubreddits(rw http.ResponseWriter, r *http.Request) {
|
|||
defer span.End()
|
||||
|
||||
c := views.NewContext(routes.Config, r)
|
||||
|
||||
var params api.ListSubredditsParams
|
||||
params.FillFromQuery(r.URL.Query())
|
||||
|
||||
var data subreddits.Data
|
||||
var err error
|
||||
data.Params.FillFromQuery(r.URL.Query())
|
||||
|
||||
data.Subreddits, err = routes.API.ListSubredditsWithCover(ctx, params)
|
||||
var err error
|
||||
data.Subreddits, err = routes.API.ListSubredditsWithCover(ctx, data.Params)
|
||||
if err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to list subreddits")
|
||||
code, message := errs.HTTPMessage(err)
|
||||
|
|
60
views/subreddits/filter.templ
Normal file
60
views/subreddits/filter.templ
Normal file
|
@ -0,0 +1,60 @@
|
|||
package subreddits
|
||||
|
||||
import "github.com/tigorlazuardi/redmage/api"
|
||||
|
||||
templ Filter(params api.ListSubredditsParams) {
|
||||
<div
|
||||
id="filter-bar"
|
||||
hx-get="/subreddits"
|
||||
hx-target="#subreddits-list"
|
||||
hx-select="#subreddits-list"
|
||||
hx-trigger="change,input delay:300ms"
|
||||
hx-include="this"
|
||||
hx-push-url="true"
|
||||
hx-swap="outerHTML"
|
||||
class="grid grid-cols-[1fr,4fr] sm:grid-cols-[1fr,4fr,1fr,4fr] items-center gap-4"
|
||||
>
|
||||
@searchInput(params)
|
||||
@nsfwSelect(params)
|
||||
@orderInput(params)
|
||||
@sortInput(params)
|
||||
</div>
|
||||
}
|
||||
|
||||
templ searchInput(params api.ListSubredditsParams) {
|
||||
<label for="search" class="label">Search</label>
|
||||
<input
|
||||
type="text"
|
||||
id="search"
|
||||
name="q"
|
||||
class="input input-bordered"
|
||||
value={ params.Q }
|
||||
placeholder="Filter Subreddit"
|
||||
/>
|
||||
}
|
||||
|
||||
templ nsfwSelect(params api.ListSubredditsParams) {
|
||||
<label for="nsfw" class="label">NSFW</label>
|
||||
<select id="nsfw" name="nsfw" class="select select-bordered">
|
||||
<option value="-1" selected?={ params.NSFW < 0 || params.NSFW > 1 }>*No Filter</option>
|
||||
<option value="0" selected?={ params.NSFW == 0 }>Hide</option>
|
||||
<option value="1" selected?={ params.NSFW == 1 }>Show Only</option>
|
||||
</select>
|
||||
}
|
||||
|
||||
templ orderInput(params api.ListSubredditsParams) {
|
||||
<label for="order" class="label">Order By</label>
|
||||
<select id="order" name="order_by" class="select select-bordered">
|
||||
<option value="updated_at" selected?={ params.OrderBy == "updated_at" }>Latest Update</option>
|
||||
<option value="created_at" selected?={ params.OrderBy == "created_at" }>Created</option>
|
||||
<option value="name" selected?={ params.OrderBy == "name" }>Name</option>
|
||||
</select>
|
||||
}
|
||||
|
||||
templ sortInput(params api.ListSubredditsParams) {
|
||||
<label for="sort" class="label">Sort</label>
|
||||
<select id="sort" name="sort" class="select select-bordered">
|
||||
<option value="desc" selected?={ params.Sort == "desc" }>Descending</option>
|
||||
<option value="asc" selected?={ params.Sort == "asc" }>Ascending</option>
|
||||
</select>
|
||||
}
|
|
@ -11,6 +11,7 @@ import "github.com/tigorlazuardi/redmage/views/icons"
|
|||
type Data struct {
|
||||
Subreddits api.ListSubredditsResult
|
||||
Error string
|
||||
Params api.ListSubredditsParams
|
||||
}
|
||||
|
||||
templ View(c *views.Context, data Data) {
|
||||
|
@ -34,16 +35,21 @@ templ Content(c *views.Context, data Data) {
|
|||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
if data.Subreddits.Total == 0 {
|
||||
<h3>No Subreddits Found</h3>
|
||||
<p>Click <a class="text-primary" href="/subreddits/add">here</a> to add a new subreddit.</p>
|
||||
} else {
|
||||
<h2>{ strconv.FormatInt(data.Subreddits.Total, 10) } Subreddits Registered</h2>
|
||||
if data.Subreddits.Total > 0 {
|
||||
@Filter(data.Params)
|
||||
}
|
||||
<div class="flex flex-wrap gap-1 justify-around" hx-boost="true">
|
||||
for _, subreddit := range data.Subreddits.Data {
|
||||
@SubredditCard(c, subreddit)
|
||||
<div id="subreddits-list">
|
||||
if data.Subreddits.Total == 0 {
|
||||
<h3>No Subreddits Found</h3>
|
||||
<p>Click <a class="text-primary" href="/subreddits/add">here</a> to add a new subreddit.</p>
|
||||
} else {
|
||||
<h2 class="my-4">{ strconv.FormatInt(data.Subreddits.Total, 10) } Subreddits Registered</h2>
|
||||
}
|
||||
<div class="flex flex-wrap gap-1 justify-around" hx-boost="true">
|
||||
for _, subreddit := range data.Subreddits.Data {
|
||||
@SubredditCard(c, subreddit)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</main>
|
||||
|
|
Loading…
Reference in a new issue