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
|
|
@ -21,6 +21,7 @@ const maxExportFaves = 100000
|
|||
type ExportFave struct {
|
||||
Description string `json:"description"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
Privacy string `json:"privacy"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
|
|
@ -57,6 +58,7 @@ func (h *Handler) handleExportJSON(w http.ResponseWriter, r *http.Request) {
|
|||
export[i] = ExportFave{
|
||||
Description: f.Description,
|
||||
URL: f.URL,
|
||||
Notes: f.Notes,
|
||||
Privacy: f.Privacy,
|
||||
Tags: tags,
|
||||
CreatedAt: f.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
|
|
@ -89,7 +91,7 @@ func (h *Handler) handleExportCSV(w http.ResponseWriter, r *http.Request) {
|
|||
w.Header().Set("Content-Disposition", "attachment; filename=favoritter.csv")
|
||||
|
||||
cw := csv.NewWriter(w)
|
||||
cw.Write([]string{"description", "url", "privacy", "tags", "created_at"})
|
||||
cw.Write([]string{"description", "url", "notes", "privacy", "tags", "created_at"})
|
||||
|
||||
for _, f := range faves {
|
||||
tags := make([]string, len(f.Tags))
|
||||
|
|
@ -99,6 +101,7 @@ func (h *Handler) handleExportCSV(w http.ResponseWriter, r *http.Request) {
|
|||
cw.Write([]string{
|
||||
f.Description,
|
||||
f.URL,
|
||||
f.Notes,
|
||||
f.Privacy,
|
||||
strings.Join(tags, ","),
|
||||
f.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
|
|
@ -159,7 +162,7 @@ func (h *Handler) handleImportPost(w http.ResponseWriter, r *http.Request) {
|
|||
privacy = user.DefaultFavePrivacy
|
||||
}
|
||||
|
||||
fave, err := h.deps.Faves.Create(user.ID, ef.Description, ef.URL, "", privacy)
|
||||
fave, err := h.deps.Faves.Create(user.ID, ef.Description, ef.URL, "", ef.Notes, privacy)
|
||||
if err != nil {
|
||||
slog.Error("import: create fave error", "error", err)
|
||||
continue
|
||||
|
|
@ -213,6 +216,9 @@ func parseImportCSV(r io.Reader) ([]ExportFave, error) {
|
|||
if idx, ok := colMap["url"]; ok && idx < len(row) {
|
||||
f.URL = row[idx]
|
||||
}
|
||||
if idx, ok := colMap["notes"]; ok && idx < len(row) {
|
||||
f.Notes = row[idx]
|
||||
}
|
||||
if idx, ok := colMap["privacy"]; ok && idx < len(row) {
|
||||
f.Privacy = row[idx]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue