summaryrefslogtreecommitdiff
path: root/vrsite/page.go
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-30 17:05:12 -0300
committerGabriel Schneider <[email protected]>2026-07-30 17:56:23 -0300
commit8ec4e135e318c7799b2576a8729493c063da4a97 (patch)
treeab37cdbb7f478eb996264cf941891f127f303c85 /vrsite/page.go
parentcb05c363045bf0e7af5858f6d7bc26f026fa9d70 (diff)
downloadnotevi-8ec4e135e318c7799b2576a8729493c063da4a97.tar.gz
notevi-8ec4e135e318c7799b2576a8729493c063da4a97.zip
Diffstat (limited to 'vrsite/page.go')
-rw-r--r--vrsite/page.go106
1 files changed, 90 insertions, 16 deletions
diff --git a/vrsite/page.go b/vrsite/page.go
index 71a8343..2974eec 100644
--- a/vrsite/page.go
+++ b/vrsite/page.go
@@ -16,16 +16,29 @@ import (
type page struct {
Site *Site
Title string
- Kind string // index | file | files | notes | jj | change
+ Kind string // index | file | files | notes | jj | change | session
Root string // static: relative prefix; live: "/"
Live bool
- Rev string // revision being browsed ("" = the site change)
- ChangeID string // resolved change id for Rev
+ Rev string // revision being browsed ("" = the change the log points at)
+ ChangeID string // resolved change id for Rev — what pages name and link
+ Commit string // the commit under it — what content is read and cached at
+ Default string // the change the log points at
+ Path string // this request's path, so the change bar can re-aim it
Current string // current file path, for the tree
User string // who web comments are attributed to
- Tree template.HTML
- File *File
+ // what this view is scoped to. Scope is "change" (only what was recorded
+ // at ChangeID) or "all"; ScopeEmpty means "change" was asked for but
+ // nothing was ever recorded there, so the whole log is showing instead.
+ Scope string
+ ScopeEmpty bool
+ Here int // notes recorded at this change
+ Elsewhere int // notes recorded at any other change
+ ChangeInfo *Row
+
+ Tree template.HTML
+ File *File
+ Files []*File // every file at this change, for counts
Notes []*Note
Filter NoteFilter
@@ -36,6 +49,7 @@ type page struct {
JJ *JJView
Change *Change
+ Conv *Conv
Err string
}
@@ -49,15 +63,54 @@ type JJView struct {
Err string
}
-func (p *page) revQuery(first bool) string {
- if p.Rev == "" || p.Rev == "@" {
+// params carries the two things every link must not lose: which change you
+// are looking at, and how wide the view is.
+func (p *page) params() string { return p.paramsWith(p.Scope) }
+
+func (p *page) paramsWith(scope string) string {
+ var q []string
+ // "@" is a revset like any other now that the default change is the log's,
+ // so dropping it here would slide the reader off the change they picked
+ if p.Rev != "" {
+ q = append(q, "rev="+url.QueryEscape(p.Rev))
+ }
+ if scope == "all" {
+ q = append(q, "scope=all")
+ }
+ if len(q) == 0 {
return ""
}
- sep := "&"
- if first {
- sep = "?"
+ return "?" + strings.Join(q, "&")
+}
+
+// ScopeHref is this same page seen with the other scope.
+func (p *page) ScopeHref(scope string) string {
+ path := p.Path
+ if path == "" {
+ path = "/"
+ }
+ return path + p.paramsWith(scope)
+}
+
+// BackHref is this page again at the change the log points at.
+func (p *page) BackHref() string {
+ q := ""
+ if p.Scope == "all" {
+ q = "?scope=all"
+ }
+ return p.JumpPath() + q
+}
+
+// JumpPath is where the change picker submits: your own page when it is one
+// that can be read at any change, the file tree otherwise.
+func (p *page) JumpPath() string {
+ switch p.Kind {
+ case "index", "file", "files", "notes":
+ if p.Path != "" {
+ return p.Path
+ }
}
- return sep + "rev=" + url.QueryEscape(p.Rev)
+ return "/files"
}
// Href maps a logical destination to a URL for this page's mode. Kinds the
@@ -70,19 +123,21 @@ func (p *page) Href(kind string, arg ...string) string {
if p.Live {
switch kind {
case "":
- return "/" + p.revQuery(true)
+ return "/" + p.params()
case "notes":
- return "/notes"
+ return "/notes" + p.params()
case "files":
- return "/files" + p.revQuery(true)
+ return "/files" + p.params()
case "tree":
- return "/tree" + p.revQuery(true)
+ return "/tree" + p.params()
case "jj":
return "/jj"
case "code":
- return "/code/" + escPath(a) + p.revQuery(true)
+ return "/code/" + escPath(a) + p.params()
case "change":
return "/change/" + a
+ case "session":
+ return "/session/" + escPath(a)
case "asset":
return "/" + a
}
@@ -118,12 +173,31 @@ func escPath(p string) string {
return strings.Join(parts, "/")
}
+// ConvHref opens the conversation a note was written in, anchored on it. It
+// needs the transcripts on this machine, so the static export has none — and
+// the conversation itself does not link back to where you already are.
+func (p *page) ConvHref(n *Note) string {
+ if !p.Live || p.Kind == "session" || n.Session == "" || safeSession(n.Session) != nil {
+ return ""
+ }
+ id := strconv.Itoa(n.ID)
+ return p.Href("session", n.Session) + "?note=" + id + "#note-" + id
+}
+
// NoteHref points at the noted line, or the note list when it is unpinned.
+// The ?note= is what turns a jump into an arrival: the page opens in notes
+// focus with the card flashed and its lines marked (see app.js).
func (p *page) NoteHref(n *Note) string {
if n.File == "" {
return p.Href("notes")
}
+ id := strconv.Itoa(n.ID)
h := p.Href("code", n.File)
+ sep := "?"
+ if strings.Contains(h, "?") {
+ sep = "&"
+ }
+ h += sep + "note=" + id
if n.Start > 0 {
h += "#L" + strconv.Itoa(n.Start)
}