feat: add notes field to favorites and enhance OG meta tags
Add an optional long-form "notes" text field to each favorite for reviews, thoughts, or extended descriptions. The field is stored in SQLite via a new migration (002_add_fave_notes.sql) and propagated through the entire stack: - Model: Notes field on Fave struct - Store: All SQL queries (Create, GetByID, Update, list methods, scanFaves) updated with notes column - Web handlers: Read/write notes in create, edit, update forms - API handlers: Notes in create, update, get, import request/response - Export: Notes included in both JSON and CSV exports - Import: Notes parsed from both JSON and CSV imports - Feed: Notes used as Atom feed item summary when present - Form template: New textarea between URL and image fields - Detail template: Display notes, enhanced og:description with cascade: notes (truncated) → URL → generic fallback text Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a8f3aa6f7e
commit
485d01ce45
14 changed files with 151 additions and 71 deletions
|
|
@ -135,6 +135,7 @@ func (h *Handler) handleCreateFave(w http.ResponseWriter, r *http.Request) {
|
|||
var req struct {
|
||||
Description string `json:"description"`
|
||||
URL string `json:"url"`
|
||||
Notes string `json:"notes"`
|
||||
Privacy string `json:"privacy"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
|
@ -151,7 +152,7 @@ func (h *Handler) handleCreateFave(w http.ResponseWriter, r *http.Request) {
|
|||
req.Privacy = user.DefaultFavePrivacy
|
||||
}
|
||||
|
||||
fave, err := h.deps.Faves.Create(user.ID, req.Description, req.URL, "", req.Privacy)
|
||||
fave, err := h.deps.Faves.Create(user.ID, req.Description, req.URL, "", req.Notes, req.Privacy)
|
||||
if err != nil {
|
||||
slog.Error("api: create fave error", "error", err)
|
||||
jsonError(w, "Internal error", http.StatusInternalServerError)
|
||||
|
|
@ -222,6 +223,7 @@ func (h *Handler) handleUpdateFave(w http.ResponseWriter, r *http.Request) {
|
|||
var req struct {
|
||||
Description string `json:"description"`
|
||||
URL string `json:"url"`
|
||||
Notes string `json:"notes"`
|
||||
Privacy string `json:"privacy"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
|
@ -237,7 +239,7 @@ func (h *Handler) handleUpdateFave(w http.ResponseWriter, r *http.Request) {
|
|||
req.Privacy = fave.Privacy
|
||||
}
|
||||
|
||||
if err := h.deps.Faves.Update(id, req.Description, req.URL, fave.ImagePath, req.Privacy); err != nil {
|
||||
if err := h.deps.Faves.Update(id, req.Description, req.URL, fave.ImagePath, req.Notes, req.Privacy); err != nil {
|
||||
slog.Error("api: update fave error", "error", err)
|
||||
jsonError(w, "Internal error", http.StatusInternalServerError)
|
||||
return
|
||||
|
|
@ -378,6 +380,7 @@ func (h *Handler) handleImport(w http.ResponseWriter, r *http.Request) {
|
|||
var faves []struct {
|
||||
Description string `json:"description"`
|
||||
URL string `json:"url"`
|
||||
Notes string `json:"notes"`
|
||||
Privacy string `json:"privacy"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
|
@ -395,7 +398,7 @@ func (h *Handler) handleImport(w http.ResponseWriter, r *http.Request) {
|
|||
if privacy != "public" && privacy != "private" {
|
||||
privacy = user.DefaultFavePrivacy
|
||||
}
|
||||
fave, err := h.deps.Faves.Create(user.ID, f.Description, f.URL, "", privacy)
|
||||
fave, err := h.deps.Faves.Create(user.ID, f.Description, f.URL, "", f.Notes, privacy)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
|
@ -446,6 +449,7 @@ func faveJSON(f *model.Fave) map[string]any {
|
|||
"id": f.ID,
|
||||
"description": f.Description,
|
||||
"url": f.URL,
|
||||
"notes": f.Notes,
|
||||
"image_path": f.ImagePath,
|
||||
"privacy": f.Privacy,
|
||||
"tags": tags,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue