Personal build of stagit static git page generator.
log | files | refs | readme | license

commit ff291d6c72608cbd385874f6cf66ba2662ed2b75
parent f6c99b65e4ee7c0dd648f7582ef848e5e3a13524
Author: Michael Skec
Date:   Sat, 11 Nov 2023 18:27:07 +1100

Implement client-side commit age

Now shows age/idle time of commits/repositories using some ugly
JavaScript.  Looks alright for now.

Diffstat:
Mstagit-index.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mstagit.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
2 files changed, 132 insertions(+), 16 deletions(-)

diff --git a/stagit-index.c b/stagit-index.c @@ -90,7 +90,12 @@ printtimeshort(FILE *fp, const git_time *intime) if (!(intm = gmtime(&t))) return; //strftime(out, sizeof(out), "%Y-%m-%d %H:%M", intm); - strftime(out, sizeof(out), "%Y-%m-%d", intm); + //strftime(out, sizeof(out), "%Y-%m-%d", intm); + + /* ISO-8601 UTC time which we convert to the local time on the page using a + * little bit of JavaScript. */ + strftime(out, sizeof(out), "%Y-%m-%dT%H:%M:%S.000Z", intm); + fputs(out, fp); } @@ -105,6 +110,7 @@ writeheader(FILE *fp) xmlencode(fp, title, strlen(title)); fprintf(fp, "</title>\n<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.png\" />\n", relpath); fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"%sstyle.css\" />\n", relpath); + fputs("</head>\n<body>\n", fp); #if LOGO fprintf(fp, "<table>\n<tr><td><img src=\"%slogo.png\" alt=\"\" width=\"32\" height=\"32\" /></td>\n" @@ -118,14 +124,64 @@ writeheader(FILE *fp) "</td></tr>\n</table>\n<hr/>\n<div id=\"content\">\n" "<table id=\"index\"><thead>\n" "<tr><td><b>Name</b></td><td><b>Description</b></td><td><b>Owner</b></td>" - "<td><b>Latest commit</b></td></tr>" + "<td><b class=\"date-idle\">Latest commit</b></td></tr>" "</thead><tbody>\n", fp); } void writefooter(FILE *fp) { - fputs("</tbody>\n</table>\n</div>\n</body>\n</html>\n", fp); + //fputs("</tbody>\n</table>\n</div>\n</body>\n</html>\n", fp); + fputs("</tbody>\n</table>\n</div>\n", fp); + + /* Some client-side JS that converts our UTC date strings to a more logical 'age' string. */ + fputs( + "<script type=\"text/javascript\">" + "/* Set date-idle titles */" + "var date_idles = document.getElementsByClassName(\"date-idle\");" + "for (var i = 0; i < date_idles.length; ++i)" + "{" + "date_idles[i].innerHTML = \"Idle\";" + "}" + "" + "/* Convert UTC dates to age strings */" + "var now = Date.now();" + "var utctimes = document.getElementsByClassName(\"age\");" + "for (var i = 0; i < utctimes.length; ++i)" + "{" + "var t = new Date(utctimes[i].innerHTML);" + "var secs = Math.abs(now - t) / 1000;" + "if (secs < 2 * 60 * 60) /* last two hours -- print minutes */" + "{" + "utctimes[i].innerHTML = Math.round(secs / 60).toString() + \" min.\";" + "continue;" + "}" + "if (secs < 2 * 60 * 60 * 24) /* last two days -- print hours */" + "{" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60)).toString() + \" hours\";" + "continue;" + "}" + "if (secs < 2 * 60 * 60 * 24 * 7) /* last two weeks -- print days */" + "{" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24)).toString() + \" days\";" + "continue;" + "}" + "if (secs < 2 * 60 * 60 * 24 * 30) /* last two months -- print weeks */" + "{" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 7)).toString() + \" weeks\";" + "continue;" + "}" + "if (secs < 2 * 60 * 60 * 24 * 365) /* last two years -- print months */" + "{" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 30)).toString() + \" months\";" + "continue;" + "}" + "/* print years */" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 365)).toString() + \" years\";" + "}" + "</script>", fp); + + fputs("</body>\n</html>\n", fp); } int @@ -170,7 +226,7 @@ writelog(FILE *fp) xmlencode(fp, description, strlen(description)); fputs("</td><td>", fp); xmlencode(fp, owner, strlen(owner)); - fputs("</td><td>", fp); + fputs("</td><td class=\"age\">", fp); if (author) printtimeshort(fp, &(author->when)); fputs("</td></tr>", fp); diff --git a/stagit.c b/stagit.c @@ -5,6 +5,7 @@ #include <errno.h> #include <libgen.h> #include <limits.h> +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -494,7 +495,12 @@ printtimeshort(FILE *fp, const git_time *intime) t = (time_t)intime->time; if (!(intm = gmtime(&t))) return; - strftime(out, sizeof(out), "%Y-%m-%d %H:%M", intm); + //strftime(out, sizeof(out), "%Y-%m-%d %H:%M", intm); + + /* ISO-8601 UTC time which we convert to the local time on the page using a + * little bit of JavaScript. */ + strftime(out, sizeof(out), "%Y-%m-%dT%H:%M:%S.000Z", intm); + fputs(out, fp); } @@ -578,9 +584,63 @@ writeheader(FILE *fp, const char *title) } void -writefooter(FILE *fp) +writefooter(FILE *fp, bool age_js) { - fputs("</div>\n</body>\n</html>\n", fp); + //fputs("</div>\n</body>\n</html>\n", fp); + + fputs("</div>\n", fp); + + if (age_js) + { + /* Some client-side JS that converts our UTC date strings to a more logical 'age' string. */ + fputs( + "<script type=\"text/javascript\">" + "/* Set date-age titles */" + "var date_ages = document.getElementsByClassName(\"date-age\");" + "for (var i = 0; i < date_ages.length; ++i)" + "{" + "date_ages[i].innerHTML = \"Age\";" + "}" + "" + "/* Convert UTC dates to age strings */" + "var now = Date.now();" + "var utctimes = document.getElementsByClassName(\"age\");" + "for (var i = 0; i < utctimes.length; ++i)" + "{" + "var t = new Date(utctimes[i].innerHTML);" + "var secs = Math.abs(now - t) / 1000;" + "if (secs < 2 * 60 * 60) /* last two hours -- print minutes */" + "{" + "utctimes[i].innerHTML = Math.round(secs / 60).toString() + \" min.\";" + "continue;" + "}" + "if (secs < 2 * 60 * 60 * 24) /* last two days -- print hours */" + "{" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60)).toString() + \" hours\";" + "continue;" + "}" + "if (secs < 2 * 60 * 60 * 24 * 7) /* last two weeks -- print days */" + "{" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24)).toString() + \" days\";" + "continue;" + "}" + "if (secs < 2 * 60 * 60 * 24 * 30) /* last two months -- print weeks */" + "{" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 7)).toString() + \" weeks\";" + "continue;" + "}" + "if (secs < 2 * 60 * 60 * 24 * 365) /* last two years -- print months */" + "{" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 30)).toString() + \" months\";" + "continue;" + "}" + "/* print years */" + "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 365)).toString() + \" years\";" + "}" + "</script>", fp); + } + + fputs("</body>\n</html>\n", fp); } size_t @@ -830,7 +890,7 @@ printshowfile(FILE *fp, struct commitinfo *ci) void writelogline(FILE *fp, struct commitinfo *ci) { - fputs("<tr><td>", fp); + fputs("<tr><td class=\"age\">", fp); if (ci->author) printtimeshort(fp, &(ci->author->when)); fputs("</td><td>", fp); @@ -908,7 +968,7 @@ writelog(FILE *fp, const git_oid *oid) fputs("<pre>", fpfile); printshowfile(fpfile, ci); fputs("</pre>\n", fpfile); - writefooter(fpfile); + writefooter(fpfile, false); checkfileerror(fpfile, path, 'w'); fclose(fpfile); } @@ -1072,7 +1132,7 @@ writeblob(git_object *obj, const char *fpath, const char *filename, size_t files else lc = writeblobhtml(fp, (git_blob *)obj); - writefooter(fp); + writefooter(fp, false); checkfileerror(fp, fpath, 'w'); fclose(fp); @@ -1242,7 +1302,7 @@ writerefs(FILE *fp) if (++count == 1) { fprintf(fp, "<h2>%s</h2><table id=\"%s\">" "<thead>\n<tr><td><b>Name</b></td>" - "<td><b>Latest commit</b></td>" + "<td><b class=\"date-age\">Latest commit</b></td>" "<td><b>Author</b></td>\n</tr>\n" "</thead><tbody>\n", titles[j], ids[j]); @@ -1253,7 +1313,7 @@ writerefs(FILE *fp) fputs("<tr><td>", fp); xmlencode(fp, s, strlen(s)); - fputs("</td><td>", fp); + fputs("</td><td class=\"age\">", fp); if (ci->author) printtimeshort(fp, &(ci->author->when)); fputs("</td><td>", fp); @@ -1418,7 +1478,7 @@ main(int argc, char *argv[]) relpath = ""; mkdir("commit", S_IRWXU | S_IRWXG | S_IRWXO); writeheader(fp, NULL); - fputs("<table id=\"log\"><thead>\n<tr><td><b>Date</b></td>" + fputs("<table id=\"log\"><thead>\n<tr><td><b class=\"date-age\">Latest commit</b></td>" "<td><b>Commit message</b></td>" "<td><b>Author</b></td><td class=\"num\" align=\"right\"><b>Files</b></td>" "<td class=\"num\" align=\"right\"><b>+</b></td>" @@ -1465,7 +1525,7 @@ main(int argc, char *argv[]) } fputs("</tbody></table>", fp); - writefooter(fp); + writefooter(fp, true); checkfileerror(fp, "log.html", 'w'); fclose(fp); @@ -1474,7 +1534,7 @@ main(int argc, char *argv[]) writeheader(fp, NULL); if (head) writefiles(fp, head); - writefooter(fp); + writefooter(fp, false); checkfileerror(fp, "files.html", 'w'); fclose(fp); @@ -1482,7 +1542,7 @@ main(int argc, char *argv[]) fp = efopen("refs.html", "w"); writeheader(fp, NULL); writerefs(fp); - writefooter(fp); + writefooter(fp, true); checkfileerror(fp, "refs.html", 'w'); fclose(fp);