diff --git a/_test-site/posts/2026/02/24-it-may-have.md b/_test-site/posts/2026/02/24-it-may-have.md new file mode 100644 index 0000000..a5cb835 --- /dev/null +++ b/_test-site/posts/2026/02/24-it-may-have.md @@ -0,0 +1,10 @@ +--- +id: Ed6vIR86gspx +title: "" +date: 2026-02-24T10:55:39Z +tags: [] +slug: /2026/02/24/it-may-have +--- +It may have been an issue with the call to air? Hmm. Will need to make sure to check that is working correctly. + +I am now updating this. I am also updating this too. \ No newline at end of file diff --git a/_test-site/posts/2026/02/24-it-will-even.md b/_test-site/posts/2026/02/24-it-will-even.md new file mode 100644 index 0000000..6abd989 --- /dev/null +++ b/_test-site/posts/2026/02/24-it-will-even.md @@ -0,0 +1,8 @@ +--- +id: bzAVD55SB2LE +title: "" +date: 2026-02-24T11:20:23Z +tags: [] +slug: /2026/02/24/it-will-even +--- +It will even do it for new posts. \ No newline at end of file diff --git a/_test-site/posts/2026/02/24-this-is-a.md b/_test-site/posts/2026/02/24-this-is-a.md new file mode 100644 index 0000000..6497e96 --- /dev/null +++ b/_test-site/posts/2026/02/24-this-is-a.md @@ -0,0 +1,12 @@ +--- +id: MFHzBhJwJCQ3 +title: "" +date: 2026-02-24T11:20:11Z +tags: [] +slug: /2026/02/24/this-is-a +--- +This is a new post, and will be saved as a draft. + +It's still a draft. But the minute I publish it, it will be updated as an updated post. You see? I'm still writing in this. + +But the minute I press enter, it will always publish. \ No newline at end of file diff --git a/_test-site/posts/2026/02/24-this-was-a.md b/_test-site/posts/2026/02/24-this-was-a.md new file mode 100644 index 0000000..00439fe --- /dev/null +++ b/_test-site/posts/2026/02/24-this-was-a.md @@ -0,0 +1,10 @@ +--- +id: -sU1lmmL7i56 +title: "" +date: 2026-02-24T11:20:44Z +tags: [] +slug: /2026/02/24/this-was-a +--- +This was a draft. + +But now it's a published post. \ No newline at end of file diff --git a/assets/js/controllers/postedit.js b/assets/js/controllers/postedit.js new file mode 100644 index 0000000..dfb3b55 --- /dev/null +++ b/assets/js/controllers/postedit.js @@ -0,0 +1,79 @@ +import { Controller } from "@hotwired/stimulus" +import { showToast } from "../services/toast"; + +export default class PosteditController extends Controller { + static values = { + saveAction: String, + }; + + connect() { + console.log("connected"); + } + + async save(ev) { + ev.preventDefault(); + + try { + await this._postForm(this.saveActionValue); + + showToast({ + title: "💾 Post Saved", + body: (this.saveActionValue === "Save Draft") ? "Post saved as draft." : "Post updated.", + }); + } catch (e) { + console.error(e); + showToast({ + title: "❌ Error", + body: "Unable to save post. Please try again later.", + }); + } + } + + async publish(ev) { + ev.preventDefault(); + + try { + await this._postForm("Publish"); + + window.location.href = this.element.getAttribute("action"); + } catch (e) { + console.error(e); + showToast({ + title: "❌ Error", + body: "Unable to publish post. Please try again later.", + }); + } + } + + async _postForm(action) { + if (this._isPosting) { + return; + } + this._isPosting = true; + + try { + const formData = new FormData(this.element); + let data = Object.fromEntries(formData.entries()); + data = {...data, action: action || 'save'}; + + const response = await fetch(this.element.getAttribute("action"), { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return response.json(); + } finally { + this._isPosting = false; + } + } + + +} \ No newline at end of file diff --git a/assets/js/controllers/postlist.js b/assets/js/controllers/postlist.js index 40e3d44..82a319f 100644 --- a/assets/js/controllers/postlist.js +++ b/assets/js/controllers/postlist.js @@ -1,5 +1,4 @@ import { Controller } from "@hotwired/stimulus" - import { showToast } from "../services/toast"; export default class PostlistController extends Controller { diff --git a/assets/js/main.js b/assets/js/main.js index b831564..a9bcc2a 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -2,7 +2,9 @@ import { Application } from "@hotwired/stimulus"; import ToastController from "./controllers/toast"; import PostlistController from "./controllers/postlist"; +import PosteditController from "./controllers/postedit"; window.Stimulus = Application.start() Stimulus.register("toast", ToastController); Stimulus.register("postlist", PostlistController); +Stimulus.register("postedit", PosteditController); diff --git a/handlers/middleware/user.go b/handlers/middleware/user.go index d36891d..94c0a83 100644 --- a/handlers/middleware/user.go +++ b/handlers/middleware/user.go @@ -13,6 +13,7 @@ func AuthUser() func(c fiber.Ctx) error { user := models.User{ ID: 1, Username: "testuser", + TimeZone: "Australia/Melbourne", } c.Locals("user", user) diff --git a/handlers/posts.go b/handlers/posts.go index ff9f609..041ec9d 100644 --- a/handlers/posts.go +++ b/handlers/posts.go @@ -39,7 +39,8 @@ func (ph PostsHandler) Index(c fiber.Ctx) error { func (ph PostsHandler) New(c fiber.Ctx) error { p := models.Post{ - GUID: models.NewNanoID(), + GUID: models.NewNanoID(), + State: models.StateDraft, } return c.Render("posts/edit", fiber.Map{ @@ -77,7 +78,7 @@ func (ph PostsHandler) Update(c fiber.Ctx) error { return err } - post, err := ph.PostService.PublishPost(c.Context(), req) + post, err := ph.PostService.UpdatePost(c.Context(), req) if err != nil { return err } diff --git a/models/users.go b/models/users.go index 13c6452..2a9da1d 100644 --- a/models/users.go +++ b/models/users.go @@ -1,7 +1,31 @@ package models +import "time" + type User struct { ID int64 Username string PasswordHashed []byte + TimeZone string +} + +func (u User) FormatTime(t time.Time) string { + if loc := getLocation(u.TimeZone); loc != nil { + return t.In(loc).Format("2006-01-02 15:04:05") + } + return t.Format("2006-01-02 15:04:05") +} + +var loadedLocation = map[string]*time.Location{} + +func getLocation(tz string) *time.Location { + if loc, ok := loadedLocation[tz]; ok { + return loc + } + loc, err := time.LoadLocation(tz) + if err != nil { + loc = time.Local + } + loadedLocation[tz] = loc + return loc } diff --git a/services/posts/create.go b/services/posts/create.go index 6d4cd94..1dc69a1 100644 --- a/services/posts/create.go +++ b/services/posts/create.go @@ -2,6 +2,7 @@ package posts import ( "context" + "strings" "time" "lmika.dev/lmika/weiro/models" @@ -9,12 +10,13 @@ import ( ) type CreatePostParams struct { - GUID string `form:"guid" json:"guid"` - Title string `form:"title" json:"title"` - Body string `form:"body" json:"body"` + GUID string `form:"guid" json:"guid"` + Title string `form:"title" json:"title"` + Body string `form:"body" json:"body"` + Action string `form:"action" json:"action"` } -func (s *Service) PublishPost(ctx context.Context, params CreatePostParams) (*models.Post, error) { +func (s *Service) UpdatePost(ctx context.Context, params CreatePostParams) (*models.Post, error) { site, ok := models.GetSite(ctx) if !ok { return nil, models.SiteRequiredError @@ -27,14 +29,28 @@ func (s *Service) PublishPost(ctx context.Context, params CreatePostParams) (*mo post.Title = params.Title post.Body = params.Body - post.PublishedAt = time.Now() + post.UpdatedAt = time.Now() post.Slug = post.BestSlug() + oldState := post.State + + switch strings.ToLower(params.Action) { + case "publish": + post.State = models.StatePublished + post.PublishedAt = time.Now() + case "save draft": + post.State = models.StateDraft + post.PublishedAt = time.Time{} + default: + // Leave unchanged + } if err := s.db.SavePost(ctx, post); err != nil { return nil, err } - s.publisher.Queue(site) + if oldState != post.State || post.State == models.StatePublished { + s.publisher.Queue(site) + } return post, nil } @@ -56,6 +72,7 @@ func (s *Service) fetchOrCreatePost(ctx context.Context, site models.Site, param GUID: params.GUID, Title: params.Title, Body: params.Body, + State: models.StateDraft, CreatedAt: time.Now(), } return post, nil diff --git a/views/posts/edit.html b/views/posts/edit.html index 6e1f10e..871f691 100644 --- a/views/posts/edit.html +++ b/views/posts/edit.html @@ -1,5 +1,9 @@ +{{ $isPublished := ne .post.State 1 }}
-
+
@@ -8,7 +12,12 @@
- + {{ if $isPublished }} + + {{ else }} + + + {{ end }}
\ No newline at end of file diff --git a/views/posts/index.html b/views/posts/index.html index 57c365c..ce934bd 100644 --- a/views/posts/index.html +++ b/views/posts/index.html @@ -23,25 +23,40 @@ {{ if $p.Title }}

{{ $p.Title }}

{{ end }} {{ $p.Body | markdown }} - {{ if $showingTrash }} -
- Restore - - - Delete -
- {{ else }} -
- Edit - - - Trash -
- {{ end }} +
+ {{ if eq .State 1 }} + {{ $.user.FormatTime .UpdatedAt }} Draft + {{ else }} + {{ $.user.FormatTime .PublishedAt }} + {{ end }} +
+ +
+ {{ if $showingTrash }} + + Restore + Delete + + {{ else }} + + Edit + Trash + + {{ end }} +
{{ if lt $i (sub (len $.posts) 1) }}
{{ end }} + {{ else }} +
+ {{ if $showingTrash }} +
🗑️
Trash is empty.
+ {{ else }} +
🌱
No posts yet. Better get writing!
+ {{ end }} +
{{ end }} \ No newline at end of file