Remove unused templates

This commit is contained in:
Sung 2025-10-19 21:08:26 -07:00
commit 6ba558de96
13 changed files with 0 additions and 601 deletions

View file

@ -1,103 +0,0 @@
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
*
* This file is part of Dnote.
*
* Dnote is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dnote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
*/
package tmpl
import (
"bytes"
"html/template"
"net/http"
"regexp"
"gorm.io/gorm"
"github.com/pkg/errors"
)
// routes
var notesPathRegex = regexp.MustCompile("^/notes/([^/]+)$")
// template names
var templateIndex = "index"
var templateNoteMetaTags = "note_metatags"
// AppShell represents the application in HTML
type AppShell struct {
DB *gorm.DB
T *template.Template
}
// ErrNotFound is an error indicating that a resource was not found
var ErrNotFound = errors.New("not found")
// NewAppShell parses the templates for the application
func NewAppShell(db *gorm.DB, content []byte) (AppShell, error) {
t, err := template.New(templateIndex).Parse(string(content))
if err != nil {
return AppShell{}, errors.Wrap(err, "parsing the index template")
}
_, err = t.New(templateNoteMetaTags).Parse(noteMetaTags)
if err != nil {
return AppShell{}, errors.Wrap(err, "parsing the note meta tags template")
}
return AppShell{DB: db, T: t}, nil
}
// Execute executes the index template
func (a AppShell) Execute(r *http.Request) ([]byte, error) {
data, err := a.getData(r)
if err != nil {
return nil, errors.Wrap(err, "getting data")
}
var buf bytes.Buffer
if err := a.T.ExecuteTemplate(&buf, templateIndex, data); err != nil {
return nil, errors.Wrap(err, "executing template")
}
return buf.Bytes(), nil
}
func (a AppShell) getData(r *http.Request) (tmplData, error) {
path := r.URL.Path
if ok, params := matchPath(path, notesPathRegex); ok {
p, err := a.newNotePage(r, params[0])
if err != nil {
return tmplData{}, errors.Wrap(err, "instantiating note page")
}
return p.getData()
}
p := defaultPage{}
return p.getData(), nil
}
// matchPath checks if the given path matches the given regular expressions
// and returns a boolean as well as any parameters from regex capture groups.
func matchPath(p string, reg *regexp.Regexp) (bool, []string) {
match := notesPathRegex.FindStringSubmatch(p)
if len(match) > 0 {
return true, match[1:]
}
return false, nil
}

View file

@ -1,51 +0,0 @@
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
*
* This file is part of Dnote.
*
* Dnote is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dnote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
*/
package tmpl
import (
"net/http"
"testing"
"github.com/dnote/dnote/pkg/assert"
"github.com/dnote/dnote/pkg/server/testutils"
"github.com/pkg/errors"
)
func TestAppShellExecute(t *testing.T) {
t.Run("home", func(t *testing.T) {
db := testutils.InitMemoryDB(t)
a, err := NewAppShell(db, []byte("<head><title>{{ .Title }}</title>{{ .MetaTags }}</head>"))
if err != nil {
t.Fatal(errors.Wrap(err, "preparing app shell"))
}
r, err := http.NewRequest("GET", "http://mock.url/", nil)
if err != nil {
t.Fatal(errors.Wrap(err, "preparing request"))
}
b, err := a.Execute(r)
if err != nil {
t.Fatal(errors.Wrap(err, "executing"))
}
assert.Equal(t, string(b), "<head><title>Dnote</title></head>", "result mismatch")
})
}

View file

@ -1,141 +0,0 @@
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
*
* This file is part of Dnote.
*
* Dnote is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dnote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
*/
package tmpl
import (
"bytes"
"fmt"
"html/template"
"net/http"
"regexp"
"strings"
"time"
"github.com/dnote/dnote/pkg/server/database"
"github.com/dnote/dnote/pkg/server/middleware"
"github.com/dnote/dnote/pkg/server/operations"
"github.com/pkg/errors"
)
var newlineRegexp = regexp.MustCompile(`\r?\n`)
// tmplData is the data to be passed to the app shell template
type tmplData struct {
Title string
MetaTags template.HTML
}
type noteMetaTagsData struct {
Title string
Description string
}
type notePage struct {
Note database.Note
T *template.Template
}
func (a AppShell) newNotePage(r *http.Request, noteUUID string) (notePage, error) {
user, _, err := middleware.AuthWithSession(a.DB, r)
if err != nil {
return notePage{}, errors.Wrap(err, "authenticating with session")
}
note, ok, err := operations.GetNote(a.DB, noteUUID, &user)
if !ok {
return notePage{}, ErrNotFound
}
if err != nil {
return notePage{}, errors.Wrap(err, "getting note")
}
return notePage{note, a.T}, nil
}
func (p notePage) getTitle() string {
note := p.Note
date := time.Unix(0, note.AddedOn).Format("Jan 2 2006")
return fmt.Sprintf("Note: %s (%s)", note.Book.Label, date)
}
func excerpt(s string, maxLen int) string {
if len(s) > maxLen {
var lastIdx int
if maxLen > 3 {
lastIdx = maxLen - 3
} else {
lastIdx = maxLen
}
return s[:lastIdx] + "..."
}
return s
}
func formatMetaDescContent(s string) string {
desc := excerpt(s, 200)
desc = strings.Trim(desc, " ")
return newlineRegexp.ReplaceAllString(desc, " ")
}
func (p notePage) getMetaTags() (template.HTML, error) {
title := p.getTitle()
desc := formatMetaDescContent(p.Note.Body)
data := noteMetaTagsData{
Title: title,
Description: desc,
}
var buf bytes.Buffer
if err := p.T.ExecuteTemplate(&buf, templateNoteMetaTags, data); err != nil {
return "", errors.Wrap(err, "executing template")
}
return template.HTML(buf.String()), nil
}
func (p notePage) getData() (tmplData, error) {
mt, err := p.getMetaTags()
if err != nil {
return tmplData{}, errors.Wrap(err, "getting meta tags")
}
dat := tmplData{
Title: p.getTitle(),
MetaTags: mt,
}
return dat, nil
}
type defaultPage struct {
}
func (p defaultPage) getData() tmplData {
return tmplData{
Title: "Dnote",
MetaTags: "",
}
}

View file

@ -1,68 +0,0 @@
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
*
* This file is part of Dnote.
*
* Dnote is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dnote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
*/
package tmpl
import (
"html/template"
"testing"
"time"
"github.com/dnote/dnote/pkg/assert"
"github.com/dnote/dnote/pkg/server/database"
"github.com/dnote/dnote/pkg/server/testutils"
"github.com/pkg/errors"
)
func TestDefaultPageGetData(t *testing.T) {
p := defaultPage{}
result := p.getData()
assert.Equal(t, result.MetaTags, template.HTML(""), "MetaTags mismatch")
assert.Equal(t, result.Title, "Dnote", "Title mismatch")
}
func TestNotePageGetData(t *testing.T) {
// Set time.Local to UTC for deterministic test
time.Local = time.UTC
db := testutils.InitMemoryDB(t)
a, err := NewAppShell(db, nil)
if err != nil {
t.Fatal(errors.Wrap(err, "preparing app shell"))
}
p := notePage{
Note: database.Note{
Book: database.Book{
Label: "vocabulary",
},
AddedOn: time.Date(2019, time.January, 2, 0, 0, 0, 0, time.UTC).UnixNano(),
},
T: a.T,
}
result, err := p.getData()
if err != nil {
t.Fatal(errors.Wrap(err, "executing"))
}
assert.NotEqual(t, result.MetaTags, template.HTML(""), "MetaTags should not be empty")
assert.Equal(t, result.Title, "Note: vocabulary (Jan 2 2019)", "Title mismatch")
}

View file

@ -1,29 +0,0 @@
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
*
* This file is part of Dnote.
*
* Dnote is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dnote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
*/
package tmpl
var noteMetaTags = `
<meta name="description" content="{{ .Description }}" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="{{ .Title }}" />
<meta name="twitter:description" content="{{ .Description }}" />
<meta name="twitter:image" content="https://dnote-asset.s3.amazonaws.com/images/logo-text-vertical.png" />
<meta name="og:image" content="https://dnote-asset.s3.amazonaws.com/images/logo-text-vertical.png" />
<meta name="og:title" content="{{ .Title }}" />
<meta name="og:description" content="{{ .Description }}" />`

View file

@ -1,20 +0,0 @@
{{define "yield"}}
<div class="container page page-mobile-full books-page mobile-fw">
<div class="page-header">
<h1 class="page-heading">Books</h1>
</div>
<div class="frame books-content">
<ul>
{{range .Books}}
<li>
<a href="/?book={{.Label}}">
{{ .Label }}
</a>
</li>
{{end}}
</ul>
</div>
</div>
{{end}}

View file

@ -1,4 +0,0 @@
{{define "yield"}}
content
{{ .Note.Body }}
{{end}}

View file

@ -1,17 +0,0 @@
{{define "book"}}
<svg
width="20px"
height="20px"
viewBox="0 0 32 32"
fill="none"
>
<title>Book</title>
<desc>Icon depicting a book</desc>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M26.5 32H5.5C3.56712 32 2 30.209 2 28V4C2 1.791 3.56712 0 5.5 0H26.5C28.4329 0 30 1.791 30 4V28C30 30.209 28.4329 32 26.5 32ZM9 4H6.20088C5.81238 4 5.5 4.357 5.5 4.8V27.199C5.5 27.642 5.81238 28 6.20088 28H9V4ZM26.5 4.8C26.5 4.357 26.1876 4 25.7991 4H23V13.594C23 14.033 22.7778 14.139 22.5048 13.827L19.9961 10.959C19.7231 10.647 19.2786 10.647 19.0048 10.959L16.4961 13.827C16.2222 14.139 16 14.033 16 13.594V4H10.75V28H25.7991C26.1876 28 26.5 27.642 26.5 27.199V4.8Z"
fill="{{ .fill }}"
/>
</svg>
{{end}}

View file

@ -1,26 +0,0 @@
{{define "caret"}}
<svg
width="12px"
height="12px"
viewBox="0 0 32 32"
fill="none"
class="icon--caret-{{ .direction }}"
>
<line
y1="-1"
x2="17.2395"
y2="-1"
transform="matrix(0.769979 0.638069 -0.653774 0.75669 3 11.5779)"
stroke="{{ .stroke }}"
stroke-width="4"
/>
<line
y1="-1"
x2="17.2045"
y2="-1"
transform="matrix(0.739684 -0.672954 0.688196 0.725524 16.2741 22.5779)"
stroke="{{ .stroke }}"
stroke-width="4"
/>
</svg>
{{end}}

View file

@ -1,91 +0,0 @@
{{define "yield"}}
<div id="T-home-page" class="container page page-mobile-full home-page">
<h1 class="sr-only">Notes</h1>
{{template "pageToolbar" dict "data" . "class" "toolbar"}}
<div class="note-group-list">
{{if eq (len .NoteGroups) 0 }}
<div class="note-group-list-empty">No notes found.</div>
{{end}}
{{range .NoteGroups}}
{{template "noteGroup" .}}
{{end}}
</div>
</div>
{{end}}
{{define "noteGroup"}}
<section class="note-group">
<header class="note-group-header">
<h2 class="date">
<time datetime="{{ toDateTime .Year .Month }}">
{{ getFullMonthName .Month }} {{ .Year }}
</time>
</h2>
</header>
<ul class="list-unstyled note-list">
{{range .Data}}
{{template "noteItem" .}}
{{end}}
</ul>
</section>
{{end}}
{{define "noteItem"}}
<li class="note-item">
<a href="/notes/{{ .UUID }}" class="link">
<div class="body">
<div class="note-header">
<h3 class="book-label">
{{ .Book.Label }}
</h3>
{{template "time" dict "value" .UpdatedAt "text" (timeAgo .UpdatedAt)}}
</div>
<div class="note-content">
{{ excerpt .Body 160 }}
</div>
</div>
</a>
</li>
{{end}}
{{define "pageToolbarContent"}}
<nav class="paginator">
<span class="paginator-info">
<span class="paginator-label">{{ .CurrentPage }}</span> of
<span class="paginator-label">{{ .MaxPage }}</span>
</span>
{{template "pager" dict "disabled" (not .HasPrev) "direction" "left" "page" (add .CurrentPage -1)}}
{{template "pager" dict "disabled" (not .HasNext) "direction" "right" "page" (add .CurrentPage 1)}}
</nav>
{{end}}
{{define "pager"}}
{{$ariaLabel := ""}}
{{if eq .direction "left"}}
{{$ariaLabel = "Previous page"}}
{{else}}
{{$ariaLabel = "Next page"}}
{{end}}
{{if .disabled}}
<span class="paginator-link disabled">
{{template "caret" dict "direction" .direction "stroke" "gray"}}
</span>
{{else}}
<a
href="/?page={{ .page }}"
aria-label="{{ $ariaLabel }}"
class="paginator-link"
>
{{template "caret" dict "direction" .direction "stroke" "black"}}
</a>
{{end}}
{{end}}

View file

@ -1,33 +0,0 @@
{{define "yield"}}
<div id="T-note-page" class="note-page">
<div class="container mobile-nopadding page page-mobile-full">
<article class="frame">
<header class="header">
<div class="header-left">
{{template "book" dict "fill" "#000000"}}
<h1 class="book-label">
<a href="/">
{{ .Note.Book.Label }}
</a>
</h1>
</div>
</header>
<section class="content-wrapper">
<div class="markdown-body">
{{ .Content }}
</div>
</section>
<footer class="footer">
<div class="ts">
<span class="ts-head">Last edit: </span>
{{ timeFormat .Note.UpdatedAt "January 02, 2006" }}
</div>
</footer>
</article>
</div>
</div>
{{end}}

View file

@ -1,5 +0,0 @@
{{define "pageToolbar"}}
<div class="partial--page-toolbar{{if .class}} {{.class}}{{end}}">
{{template "pageToolbarContent" .data}}
</div>
{{end}}

View file

@ -1,13 +0,0 @@
{{define "time"}}
{{$mobileText := defaultValue .mobileText .text}}
<span class="partial--time">
<time datetime="{{ toISOString .value }}">
<span>
<span class="text">{{ .text }}</span>
<span class="mobile-text">{{ $mobileText }}</span>
</span>
</time>
</span>
{{end}}