feat: metadata draft

This commit is contained in:
2026-02-03 09:04:11 +01:00
parent 7238d02a13
commit d6617cec02
7 changed files with 58 additions and 45 deletions

View File

@ -12,11 +12,10 @@ type Note struct {
Path string Path string
Title string Title string
Content string Content string
Size int64
// HTMLContent string // HTMLContent string
ModTime time.Time
// Directly in Note // Directly in Note
Tags []string Tags []string
CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
Published bool Published bool
} }
@ -25,8 +24,12 @@ func NewNote() *Note {
return &Note{} return &Note{}
} }
func formatDateRep(date time.Time) string {
return date.Format("2006-01-02 15:04:05")
}
func (n *Note) GetUpdateDateRep() string { func (n *Note) GetUpdateDateRep() string {
return n.UpdatedAt.Format("2006-01-02 15:04:05") return formatDateRep(n.UpdatedAt)
} }
// ExtractTitle return the first level heading content ('# title') // ExtractTitle return the first level heading content ('# title')

View File

@ -67,7 +67,7 @@ func (tm *TemplateManager) GetTemplate(td *TemplateData) (*template.Template, er
return tmpl, nil return tmpl, nil
} }
func (tm *TemplateManager) Render(w http.ResponseWriter, name string, data interface{}) error { func (tm *TemplateManager) Render(w http.ResponseWriter, name string, data any) error {
// Build the template files - include all necessary templates // Build the template files - include all necessary templates
var files []string var files []string
@ -77,6 +77,9 @@ func (tm *TemplateManager) Render(w http.ResponseWriter, name string, data inter
// Include noteList template (used by index) // Include noteList template (used by index)
files = append(files, tm.buildTemplatePath("noteList")) files = append(files, tm.buildTemplatePath("noteList"))
// Include metadata template
files = append(files, tm.buildTemplatePath("metadata"))
// Add the specific template // Add the specific template
files = append(files, tm.buildTemplatePath(name)) files = append(files, tm.buildTemplatePath(name))

View File

@ -100,6 +100,7 @@ func TestTemplateManagerRender(t *testing.T) {
writeTemplate(t, baseDir, "base.tmpl", `{{ define "base" }}<html>{{ template "content" . }}</html>{{ end }}`) writeTemplate(t, baseDir, "base.tmpl", `{{ define "base" }}<html>{{ template "content" . }}</html>{{ end }}`)
writeTemplate(t, baseDir, "noteList.tmpl", `{{ define "noteList" }}notes{{ end }}`) writeTemplate(t, baseDir, "noteList.tmpl", `{{ define "noteList" }}notes{{ end }}`)
writeTemplate(t, baseDir, "index.tmpl", `{{ define "content" }}hello{{ end }}`) writeTemplate(t, baseDir, "index.tmpl", `{{ define "content" }}hello{{ end }}`)
writeTemplate(t, baseDir, "metadata.tmpl", `{{ define "noteList" }}notes{{ end }}`)
tm := NewTemplateManager(baseDir) tm := NewTemplateManager(baseDir)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
@ -126,6 +127,7 @@ func TestTemplateManagerRender_MissingTemplate(t *testing.T) {
baseDir := t.TempDir() baseDir := t.TempDir()
writeTemplate(t, baseDir, "base.tmpl", `{{ define "base" }}<html>{{ template "content" . }}</html>{{ end }}`) writeTemplate(t, baseDir, "base.tmpl", `{{ define "base" }}<html>{{ template "content" . }}</html>{{ end }}`)
writeTemplate(t, baseDir, "noteList.tmpl", `{{ define "noteList" }}notes{{ end }}`) writeTemplate(t, baseDir, "noteList.tmpl", `{{ define "noteList" }}notes{{ end }}`)
writeTemplate(t, baseDir, "metadata.tmpl", `{{ define "noteList" }}notes{{ end }}`)
tm := NewTemplateManager(baseDir) tm := NewTemplateManager(baseDir)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()

View File

@ -45,6 +45,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// ViewState is built per-request, not shared // ViewState is built per-request, not shared
type ViewState struct { type ViewState struct {
Notes []*note.Note Notes []*note.Note
Note *note.Note
RenderedNote template.HTML RenderedNote template.HTML
SortBy string SortBy string
SearchTerm string SearchTerm string
@ -153,6 +154,7 @@ func (h *Handler) handleNotes(w http.ResponseWriter, r *http.Request) {
} }
// Add to state // Add to state
state.Note = note
state.RenderedNote = htmlContent state.RenderedNote = htmlContent
state.LastActive = hash state.LastActive = hash

View File

@ -5,44 +5,5 @@
<main> <main>
{{ .RenderedNote }} {{ .RenderedNote }}
</main> </main>
<aside class="metadata-panel"> {{ template "metadata" . }}
<section class="meta-block">
<h3>Tags</h3>
<div class="meta-tags">
<span class="tag">emacs</span>
<span class="tag">tramp</span>
<span class="tag">editing</span>
</div>
</section>
<section class="meta-block">
<h3>File Info</h3>
<ul class="meta-list">
<li><strong>Created:</strong> 2024-01-21</li>
<li><strong>Last Modified:</strong> 2026-02-01</li>
<li><strong>Size:</strong> 4.2 KB</li>
<li><strong>Hash:</strong> 81b9fe8656</li>
</ul>
</section>
<section class="meta-block">
<h3>Category</h3>
<div class="meta-category">Software Engineering</div>
</section>
<section class="meta-block">
<h3>Document Stats</h3>
<ul class="meta-list">
<li><strong>Word Count:</strong> 542</li>
<li><strong>Reading Time:</strong> 3 min</li>
<li><strong>Unique Words:</strong> 211</li>
</ul>
<!-- Placeholder for future stats such as word cloud -->
<div class="meta-stats-placeholder">
<p>Word cloud / stats visualization<br>(future)</p>
</div>
</section>
</aside>
{{ end }} {{ end }}

View File

@ -0,0 +1,43 @@
{{ define "metadata" }}
{{ if .RenderedNote }}
<aside class="metadata-panel">
<section class="meta-block">
<h3>Tags</h3>
<div class="meta-tags">
<span class="tag">emacs</span>
<span class="tag">tramp</span>
<span class="tag">editing</span>
</div>
</section>
<section class="meta-block">
<h3>File Info</h3>
<ul class="meta-list">
<li><strong>Last Modified:</strong>{{ .Note.GetUpdateDateRep }}</li>
<li><strong>Size:</strong> {{ .Note.Size }}</li>
<li><strong>Hash:</strong> {{ .Note.ID }}</li>
</ul>
</section>
<section class="meta-block">
<h3>Category</h3>
<div class="meta-category">Software Engineering</div>
</section>
<section class="meta-block">
<h3>Document Stats</h3>
<ul class="meta-list">
<li><strong>Word Count:</strong> 542</li>
<li><strong>Unique Words:</strong> 211</li>
</ul>
<!-- Placeholder for future stats such as word cloud -->
<div class="meta-stats-placeholder">
<p>Word cloud / stats visualization<br>(future)</p>
</div>
</section>
</aside>
{{ end }}
{{ end }}

View File

@ -27,7 +27,6 @@
{{ range .Notes }} {{ range .Notes }}
<li {{ if eq .ID $.LastActive }}class="active-note"{{ end }}> <li {{ if eq .ID $.LastActive }}class="active-note"{{ end }}>
<div class="note-title"> <div class="note-title">
<input type="checkbox"/>
<a href="/notes/{{ .ID }}" data-hash="{{ .ID }}">{{ if ge (len .Title) 30 }}{{printf "%.30s" .Title }}[...]{{ else }} {{ .Title }}{{ end }}</a> <a href="/notes/{{ .ID }}" data-hash="{{ .ID }}">{{ if ge (len .Title) 30 }}{{printf "%.30s" .Title }}[...]{{ else }} {{ .Title }}{{ end }}</a>
</div> </div>
<span class="last-modified">{{ .GetUpdateDateRep }}</span> <span class="last-modified">{{ .GetUpdateDateRep }}</span>