Live relative-time counters via shared [data-ts] ticker in layout foot (#46)
This commit is contained in:
@@ -127,6 +127,7 @@ func (a *apiServer) renderPaste(w http.ResponseWriter, row *PasteRow, justCreate
|
|||||||
"LineCount": lines,
|
"LineCount": lines,
|
||||||
"SizeBytes": len(row.Content),
|
"SizeBytes": len(row.Content),
|
||||||
"CreatedAgo": agoString(row.CreatedAt),
|
"CreatedAgo": agoString(row.CreatedAt),
|
||||||
|
"CreatedAtUnix": row.CreatedAt,
|
||||||
"ViewCount": row.ViewCount,
|
"ViewCount": row.ViewCount,
|
||||||
"Visibility": row.Visibility,
|
"Visibility": row.Visibility,
|
||||||
"ExpiresAt": row.ExpiresAt.Valid,
|
"ExpiresAt": row.ExpiresAt.Valid,
|
||||||
@@ -179,13 +180,13 @@ func (a *apiServer) handlePasteView(w http.ResponseWriter, r *http.Request) {
|
|||||||
a.renderPaste(w, row, false, "")
|
a.renderPaste(w, row, false, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
renderPage(w, "unlock.html", map[string]any{"Page": "unlock", "ID": row.ID, "Wrong": true, "CreatedAgo": agoString(row.CreatedAt)})
|
renderPage(w, "unlock.html", map[string]any{"Page": "unlock", "ID": row.ID, "Wrong": true, "CreatedAgo": agoString(row.CreatedAt), "CreatedAtUnix": row.CreatedAt})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// check cookie
|
// check cookie
|
||||||
c, err := r.Cookie("pw_" + row.ID)
|
c, err := r.Cookie("pw_" + row.ID)
|
||||||
if err != nil || c.Value != "1" {
|
if err != nil || c.Value != "1" {
|
||||||
renderPage(w, "unlock.html", map[string]any{"Page": "unlock", "ID": row.ID, "Wrong": false, "CreatedAgo": agoString(row.CreatedAt)})
|
renderPage(w, "unlock.html", map[string]any{"Page": "unlock", "ID": row.ID, "Wrong": false, "CreatedAgo": agoString(row.CreatedAt), "CreatedAtUnix": row.CreatedAt})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-1
@@ -1 +1,21 @@
|
|||||||
{{define "foot"}}{{end}}
|
{{define "foot"}}<script>
|
||||||
|
// live relative-time counters (#46): tick any [data-ts] (epoch seconds) every second
|
||||||
|
(function () {
|
||||||
|
function fmt(ts) {
|
||||||
|
const s = Math.max(0, Math.floor(Date.now() / 1000) - ts);
|
||||||
|
if (s < 60) return s + 's ago';
|
||||||
|
if (s < 3600) return Math.floor(s / 60) + 'm ago';
|
||||||
|
if (s < 86400) return Math.floor(s / 3600) + 'h ago';
|
||||||
|
return Math.floor(s / 86400) + 'd ago';
|
||||||
|
}
|
||||||
|
function tick() {
|
||||||
|
document.querySelectorAll('[data-ts]').forEach(el => {
|
||||||
|
const ts = parseInt(el.dataset.ts, 10);
|
||||||
|
if (!isNaN(ts)) el.textContent = fmt(ts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
document.addEventListener('DOMContentLoaded', tick);
|
||||||
|
tick();
|
||||||
|
})();
|
||||||
|
</script>{{end}}
|
||||||
@@ -118,7 +118,7 @@ async function load() {
|
|||||||
`<tr class="row" data-href="/${esc(it.id)}"><td><a class="slug" href="/${esc(it.id)}">${esc(it.id)}</a>` +
|
`<tr class="row" data-href="/${esc(it.id)}"><td><a class="slug" href="/${esc(it.id)}">${esc(it.id)}</a>` +
|
||||||
(it.title ? `<div class="paste-sub">${esc(it.title)}</div>` : `<div class="paste-sub dim">none</div>`) + `</td>` +
|
(it.title ? `<div class="paste-sub">${esc(it.title)}</div>` : `<div class="paste-sub dim">none</div>`) + `</td>` +
|
||||||
`<td><span class="badge">${esc(it.language || 'text')}</span></td>` +
|
`<td><span class="badge">${esc(it.language || 'text')}</span></td>` +
|
||||||
`<td class="dim">${fmtSize(it.size)}</td><td class="dim">${it.view_count}</td><td class="dim">${ago(it.created_at)}</td>` +
|
`<td class="dim">${fmtSize(it.size)}</td><td class="dim">${it.view_count}</td><td class="dim" data-ts="${it.created_at}">${ago(it.created_at)}</td>` +
|
||||||
(it.custom_slug ? `<td><a class="slug url-link" href="/${esc(it.custom_slug)}">/${esc(it.custom_slug)}</a></td>` : `<td class="dim">none</td>`) +
|
(it.custom_slug ? `<td><a class="slug url-link" href="/${esc(it.custom_slug)}">/${esc(it.custom_slug)}</a></td>` : `<td class="dim">none</td>`) +
|
||||||
`<td class="dim"><a class="id-link" href="/${esc(it.id)}">${esc(it.id)}</a></td></tr>`
|
`<td class="dim"><a class="id-link" href="/${esc(it.id)}">${esc(it.id)}</a></td></tr>`
|
||||||
).join('');
|
).join('');
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<span class="stats-k">Language</span><span class="stats-v">{{if .Language}}{{.Language}}{{else}}text{{end}}</span>
|
<span class="stats-k">Language</span><span class="stats-v">{{if .Language}}{{.Language}}{{else}}text{{end}}</span>
|
||||||
<span class="stats-k">Size</span><span class="stats-v">{{.SizeHuman}} ({{.LineCount}} lines)</span>
|
<span class="stats-k">Size</span><span class="stats-v">{{.SizeHuman}} ({{.LineCount}} lines)</span>
|
||||||
<span class="stats-k">Views</span><span class="stats-v">{{.ViewCount}}</span>
|
<span class="stats-k">Views</span><span class="stats-v">{{.ViewCount}}</span>
|
||||||
<span class="stats-k">Created</span><span class="stats-v">{{.CreatedAgo}}</span>
|
<span class="stats-k">Created</span><span class="stats-v" data-ts="{{.CreatedAtUnix}}">{{.CreatedAgo}}</span>
|
||||||
{{if .ExpiresAt}}<span class="stats-k">Expires</span><span class="stats-v">in {{.ExpiresIn}}</span>{{end}}
|
{{if .ExpiresAt}}<span class="stats-k">Expires</span><span class="stats-v">in {{.ExpiresIn}}</span>{{end}}
|
||||||
<span class="stats-k">Password</span><span class="stats-v">{{if .HasPassword}}protected{{else}}none{{end}}</span>
|
<span class="stats-k">Password</span><span class="stats-v">{{if .HasPassword}}protected{{else}}none{{end}}</span>
|
||||||
{{if .BurnAfterRead}}<span class="stats-k">Burn</span><span class="stats-v">burn after read</span>{{end}}
|
{{if .BurnAfterRead}}<span class="stats-k">Burn</span><span class="stats-v">burn after read</span>{{end}}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<button class="btn" type="submit">Unlock</button>
|
<button class="btn" type="submit">Unlock</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="foot">Created {{.CreatedAgo}}</div>
|
<div class="foot">Created <span data-ts="{{.CreatedAtUnix}}">{{.CreatedAgo}}</span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
Reference in New Issue
Block a user