commit 868dbf75c016b6c2b949a0e1828476e0b8d7bb7b
parent 8ff234c24d132d371aa89b497aacf5ffaa9a1152
Author: brookjeynes <me@brookjeynes.dev>
Date: Thu, 18 Jun 2026 08:54:50 +1000
feat: write to file
Signed-off-by: brookjeynes <me@brookjeynes.dev>
Diffstat:
| M | main.c | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- |
| A | style.css | | | 29 | +++++++++++++++++++++++++++++ |
2 files changed, 87 insertions(+), 10 deletions(-)
diff --git a/main.c b/main.c
@@ -5,6 +5,31 @@
#include <string.h>
#include <time.h>
+#define DAYS_PER_YEAR 365
+#define HOURS_PER_DAY 24
+#define MINUTES_PER_HOUR 60
+#define SECONDS_PER_MINUTE 60
+
+char *bubble_variant(int count) {
+ if (count > 13) {
+ return "-heavy";
+ }
+
+ if (count > 8) {
+ return "-medium";
+ }
+
+ if (count > 4) {
+ return "-light";
+ }
+
+ if (count > 0) {
+ return "-lightest";
+ }
+
+ return "";
+}
+
typedef struct {
char date[11]; // "YYYY-MM-DD\0"
int count;
@@ -19,13 +44,19 @@ int main(int argc, char *argv[]) {
}
char *author_email = argv[1];
- commits_by_date commit_tracker[365];
+ if (argc == 2) {
+ fprintf(stderr, "err: abs repo path required");
+ exit(1);
+ }
+ char *repo_path = argv[2];
+
+ commits_by_date commit_tracker[DAYS_PER_YEAR];
int unique_dates = 0;
git_libgit2_init();
git_repository *repo = NULL;
- if ((error = git_repository_open(&repo, "../jido")) < 0) {
+ if ((error = git_repository_open(&repo, repo_path)) < 0) {
const git_error *e = git_error_last();
printf("err: %d/%d: %s\n", error, e->klass, e->message);
exit(error);
@@ -56,7 +87,8 @@ int main(int argc, char *argv[]) {
}
const time_t now = time(NULL);
- const time_t year_behind = now - (365 * 24 * 60 * 60);
+ const time_t year_behind = now - (DAYS_PER_YEAR * HOURS_PER_DAY *
+ MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
git_oid id;
while (!git_revwalk_next(&id, walker)) {
@@ -96,7 +128,7 @@ int main(int argc, char *argv[]) {
}
if (found == 0) {
- if (unique_dates < 365) {
+ if (unique_dates < DAYS_PER_YEAR) {
strcpy(commit_tracker[unique_dates].date, buf);
commit_tracker[unique_dates].count = 1;
unique_dates++;
@@ -104,12 +136,19 @@ int main(int argc, char *argv[]) {
}
}
- time_t curr_day = now;
- while (curr_day > year_behind) {
+ printf("<html lang=\"en\">");
+ printf("<head>");
+ printf("<link rel=\"stylesheet\" href=\"./style.css\" type=\"text/css\"/>");
+ printf("</head>");
+ printf("<body>");
+ printf("<div class=\"heatmap-grid\">");
+
+ time_t day = year_behind;
+ while (day < now) {
struct tm *lt;
char buf[11];
- lt = localtime(&curr_day);
+ lt = localtime(&day);
if (strftime(buf, sizeof(buf), "%Y-%m-%d", lt) == 0) {
fprintf(stderr, "err: failed to get print time\n");
exit(1);
@@ -124,14 +163,23 @@ int main(int argc, char *argv[]) {
}
if (found == -1) {
- printf("%s: 0\n", buf);
+ printf(
+ "<div class=\"heatmap-bubble %s\" title=\"0 sessions on %s\"></div>",
+ bubble_variant(0), buf);
} else {
- printf("%s: %d\n", buf, commit_tracker[found].count);
+ int commits = commit_tracker[found].count;
+ printf(
+ "<div class=\"heatmap-bubble %s\" title=\"%d sessions on %s\"></div>",
+ bubble_variant(commits), commits, buf);
}
- curr_day -= (24 * 60 * 60);
+ day += (24 * 60 * 60);
}
+ printf("</div>");
+ printf("</body>");
+ printf("</html>");
+
git_libgit2_shutdown();
return 0;
diff --git a/style.css b/style.css
@@ -0,0 +1,29 @@
+.heatmap-grid {
+ display: grid;
+ grid-template-rows: repeat(7, minmax(0, 1fr));
+ grid-auto-flow: column;
+ gap: 0.25rem;
+}
+
+.heatmap-bubble {
+ width: 1rem;
+ height: 1rem;
+ border-radius: 0.25rem;
+ background-color: #eff2f5;
+
+ &.-lightest {
+ background-color: #aceebb;
+ }
+
+ &.-light {
+ background-color: #4ac26b;
+ }
+
+ &.-medium {
+ background-color: #2da44e;
+ }
+
+ &.-heavy {
+ background-color: #116329;
+ }
+}