home: recently added images now separated per subreddit
This commit is contained in:
parent
141abc130e
commit
6eed661f52
|
@ -7,7 +7,7 @@ args_bin = ["serve"]
|
|||
bin = "./tmp/main"
|
||||
cmd = "go build -o ./tmp/main ."
|
||||
delay = 1000
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules"]
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules", "out"]
|
||||
exclude_file = []
|
||||
exclude_regex = [
|
||||
"_test.go",
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -30,6 +30,8 @@ public/htmx*.js
|
|||
db/queries/**/*.go
|
||||
*.db
|
||||
|
||||
public/*.min.js
|
||||
|
||||
models/
|
||||
|
||||
/out
|
||||
|
|
12
Makefile
12
Makefile
|
@ -37,6 +37,16 @@ build-dependencies:
|
|||
echo "Htmx response targets not found, installing it"
|
||||
curl -o public/htmx-response-targets-1.9.11.min.js https://cdnjs.cloudflare.com/ajax/libs/htmx/1.9.11/ext/response-targets.min.js
|
||||
fi
|
||||
@if [ ! -f "public/dayjs-1.11.10.min.js" ]; then
|
||||
mkdir -p public
|
||||
echo "Dayjs not found, installing it"
|
||||
curl -o public/dayjs-1.11.10.min.js https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.10/dayjs.min.js
|
||||
fi
|
||||
@if [ ! -f "public/dayjs-relativeTime-1.11.10.min.js" ]; then
|
||||
mkdir -p public
|
||||
echo "Dayjs Relative Time not found, installing it"
|
||||
curl -o public/dayjs-relativeTime-1.11.10.min.js https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.10/plugin/relativeTime.min.js
|
||||
fi
|
||||
|
||||
build: build-dependencies prepare
|
||||
go build -o redmage
|
||||
|
@ -57,4 +67,4 @@ migrate-redo:
|
|||
@goose redo
|
||||
|
||||
migrate-up:
|
||||
@goose up
|
||||
@goose up
|
||||
|
|
|
@ -31,7 +31,8 @@ func (routes *Routes) PageHome(rw http.ResponseWriter, r *http.Request) {
|
|||
|
||||
imageListParams := api.ImageListParams{}
|
||||
imageListParams.FillFromQuery(r.URL.Query())
|
||||
imageListParams.CreatedAt = time.Now().Add(-time.Hour * 24 * 3) // images in the last 3 days.
|
||||
imageListParams.CreatedAt = time.Now().Add(-time.Hour * 24) // images in the last 24 hours
|
||||
imageListParams.Limit = 0
|
||||
|
||||
imageList, err := routes.API.ImagesListWithDevicesAndSubreddits(ctx, imageListParams)
|
||||
if err != nil {
|
||||
|
@ -44,7 +45,7 @@ func (routes *Routes) PageHome(rw http.ResponseWriter, r *http.Request) {
|
|||
|
||||
data := homeview.Data{
|
||||
SubredditsList: list,
|
||||
RecentlyAddedImages: imageList,
|
||||
RecentlyAddedImages: homeview.NewRecentlyAddedImages(imageList.Images),
|
||||
Error: err,
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ templ Head(vc *views.Context, extras ...templ.Component) {
|
|||
<link rel="icon" href="/public/favicon.svg"/>
|
||||
<script src="/public/htmx-1.9.11.min.js"></script>
|
||||
<script src="/public/htmx-response-targets-1.9.11.min.js"></script>
|
||||
<script src="/public/dayjs-1.11.10.min.js"></script>
|
||||
<script src="/public/dayjs-relativeTime-1.11.10.min.js"></script>
|
||||
<script>dayjs.extend(window.dayjs_plugin_relativeTime)</script>
|
||||
if vc.Config.Bool("http.hotreload") {
|
||||
<script src="/public/hot_reload.js"></script>
|
||||
}
|
||||
|
@ -20,5 +23,6 @@ templ Head(vc *views.Context, extras ...templ.Component) {
|
|||
}
|
||||
|
||||
templ HeadTitle(name string) {
|
||||
<title>{name}</title>
|
||||
}
|
||||
<title>{ name }</title>
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,8 @@ package homeview
|
|||
|
||||
import "github.com/tigorlazuardi/redmage/views/components"
|
||||
import "github.com/tigorlazuardi/redmage/views"
|
||||
import "github.com/tigorlazuardi/redmage/api"
|
||||
|
||||
type Data struct {
|
||||
SubredditsList api.ListSubredditsResult
|
||||
RecentlyAddedImages api.ImageListResult
|
||||
Error error
|
||||
}
|
||||
import "github.com/tigorlazuardi/redmage/views/utils"
|
||||
import "time"
|
||||
|
||||
templ Home(c *views.Context, data Data) {
|
||||
@components.Doctype() {
|
||||
|
@ -29,12 +24,18 @@ templ home(_ *views.Context, data Data) {
|
|||
<div class="prose">
|
||||
<section class="mb-4 mx-auto">
|
||||
<h1>Recently Added</h1>
|
||||
@RecentlyAddedImageList(data.RecentlyAddedImages.Images, 0)
|
||||
for _, deviceMapValue := range data.RecentlyAddedImages {
|
||||
<h2>{ deviceMapValue.device.Name }</h2>
|
||||
for _, subreddit := range deviceMapValue.subreddits {
|
||||
<h4>{ subreddit.subreddit.Name }</h4>
|
||||
@RecentlyAddedImageList(subreddit.images, 0)
|
||||
}
|
||||
}
|
||||
</section>
|
||||
<section>
|
||||
<h1>Subreddits</h1>
|
||||
for _, subreddit := range data.SubredditsList.Data {
|
||||
<h3>{ subreddit.Name } - { subreddit.Schedule }</h3>
|
||||
<h3>{ subreddit.Name } - { utils.NextScheduleTime(subreddit.Schedule).Format(time.RubyDate) }</h3>
|
||||
}
|
||||
</section>
|
||||
</div>
|
||||
|
|
48
views/homeview/homeview_data.go
Normal file
48
views/homeview/homeview_data.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package homeview
|
||||
|
||||
import (
|
||||
"github.com/tigorlazuardi/redmage/api"
|
||||
"github.com/tigorlazuardi/redmage/models"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
SubredditsList api.ListSubredditsResult
|
||||
RecentlyAddedImages RecentlyAddedImages
|
||||
Error error
|
||||
}
|
||||
|
||||
type RecentlyAddedImages = map[int32]deviceMapValue
|
||||
|
||||
type deviceMapValue struct {
|
||||
device *models.Device
|
||||
subreddits map[int32]subredditMapValue
|
||||
}
|
||||
|
||||
type subredditMapValue struct {
|
||||
subreddit *models.Subreddit
|
||||
images []*models.Image
|
||||
}
|
||||
|
||||
func NewRecentlyAddedImages(images models.ImageSlice) RecentlyAddedImages {
|
||||
r := make(RecentlyAddedImages)
|
||||
for _, image := range images {
|
||||
if image.R.Device == nil || image.R.Subreddit == nil {
|
||||
continue
|
||||
}
|
||||
if _, ok := r[image.R.Device.ID]; !ok {
|
||||
r[image.R.Device.ID] = deviceMapValue{
|
||||
device: image.R.Device,
|
||||
subreddits: make(map[int32]subredditMapValue),
|
||||
}
|
||||
}
|
||||
if _, ok := r[image.R.Device.ID].subreddits[image.R.Subreddit.ID]; !ok {
|
||||
r[image.R.Device.ID].subreddits[image.R.Subreddit.ID] = subredditMapValue{}
|
||||
}
|
||||
images := append(r[image.R.Device.ID].subreddits[image.R.Subreddit.ID].images, image)
|
||||
r[image.R.Device.ID].subreddits[image.R.Subreddit.ID] = subredditMapValue{
|
||||
subreddit: image.R.Subreddit,
|
||||
images: images,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
|
@ -3,6 +3,7 @@ package homeview
|
|||
import "github.com/tigorlazuardi/redmage/models"
|
||||
import "github.com/tigorlazuardi/redmage/api/reddit"
|
||||
import "fmt"
|
||||
import "github.com/tigorlazuardi/redmage/views/utils"
|
||||
|
||||
type ImageCardOption uint
|
||||
|
||||
|
@ -38,6 +39,9 @@ templ RecentlyAddedImageCard(data *models.Image, opts ImageCardOption) {
|
|||
>{ data.Title }</a>
|
||||
}
|
||||
<a class="text-primary-content underline" href={ templ.URL(data.PosterURL) }>{ data.Poster }</a>
|
||||
<div>
|
||||
@utils.RelativeTimeNode(fmt.Sprintf("relative-time-%s", data.PostName), data.CreatedAt)
|
||||
</div>
|
||||
<div class="card-actions justify-between">
|
||||
if data.R.Subreddit != nil {
|
||||
if !opts.Has(HideSubreddit) {
|
||||
|
|
40
views/utils/relative_schedule_time.templ
Normal file
40
views/utils/relative_schedule_time.templ
Normal file
|
@ -0,0 +1,40 @@
|
|||
package utils
|
||||
|
||||
import "strings"
|
||||
|
||||
// RelativeTimeText updates the text content of the element to be a relative time text.
|
||||
//
|
||||
// Every second it updates the text content to be the relative time text of the input string.
|
||||
|
||||
script RelativeFromTimeText(id string, time string) {
|
||||
const el = document.getElementById(id)
|
||||
|
||||
const timeText = dayjs(time).fromNow()
|
||||
el.textContent = timeText
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const timeText = dayjs(time).fromNow()
|
||||
el.textContent = timeText
|
||||
}, 1000)
|
||||
|
||||
const obs = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
for (const removed of mutation.removedNodes) {
|
||||
if (el === removed) {
|
||||
clearInterval(interval)
|
||||
obs.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
obs.observe(el.parentNode, { childList: true })
|
||||
}
|
||||
|
||||
templ RelativeTimeNode(id string, time string, class ...string) {
|
||||
<span
|
||||
id={ id }
|
||||
class={ strings.Join(class, " ") }
|
||||
>{ time }</span>
|
||||
@RelativeFromTimeText(id, time)
|
||||
}
|
17
views/utils/schedule.go
Normal file
17
views/utils/schedule.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
var cronParser = cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
|
||||
|
||||
func NextScheduleTime(in string) (out time.Time) {
|
||||
s, err := cronParser.Parse(in)
|
||||
if err != nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return s.Next(time.Now())
|
||||
}
|
Loading…
Reference in a new issue