diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-30 17:05:12 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-07-30 17:56:23 -0300 |
| commit | 8ec4e135e318c7799b2576a8729493c063da4a97 (patch) | |
| tree | ab37cdbb7f478eb996264cf941891f127f303c85 /vrsite/page.go | |
| parent | cb05c363045bf0e7af5858f6d7bc26f026fa9d70 (diff) | |
| download | notevi-8ec4e135e318c7799b2576a8729493c063da4a97.tar.gz notevi-8ec4e135e318c7799b2576a8729493c063da4a97.zip | |
Diffstat (limited to 'vrsite/page.go')
| -rw-r--r-- | vrsite/page.go | 106 |
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) } |
