src/html.cpp

changeset 56
3d2720f95cfb
parent 54
586dcd606e47
--- a/src/html.cpp	Sat Jun 28 11:32:08 2025 +0200
+++ b/src/html.cpp	Tue Jul 15 19:14:29 2025 +0200
@@ -187,13 +187,33 @@
                         const summaries = JSON.parse(this.dataset.summaries);
 
                         // Create popup content
-                        let content = `<span class="close-btn">×</span>
-                                      <h3>${date}: ${summaries.length} commit${summaries.length !== '1' ? 's' : ''}</h3>`;
-                        content += '<ul>';
-                        summaries.forEach(summary => {
-                            content += `<li>${summary}</li>`;
-                        });
-                        content += '</ul>';
+                        let content = '<span class="close-btn">×</span>';
+                        if (Array.isArray(summaries)) {
+                            content += `<h3>${date}: ${summaries.length} commit${summaries.length !== 1 ? 's' : ''}</h3>`;
+                            content += '<ul>';
+                            summaries.forEach(summary => {
+                                content += `<li>${summary}</li>`;
+                            });
+                            content += '</ul>';
+                        } else {
+                            const repos = Object.keys(summaries).sort();
+                            let total_commits = 0;
+                            for (const repo of repos) total_commits += summaries[repo].length;
+                            content += `<h3>${date}: ${total_commits} commit${total_commits !== 1 ? 's' : ''}</h3>`;
+                            for (const repo of repos) {
+                                const commits = summaries[repo];
+                                if (repos.length > 1) {
+                                    content += `<h4>${repo} (${commits.length} commit${commits.length !== 1 ? 's' : ''})</h4>`;
+                                } else {
+                                    content += `<h4>${repo}</h4>`;
+                                }
+                                content += '<ul>';
+                                commits.forEach(commit => {
+                                    content += `<li>${commit}</li>`;
+                                });
+                                content += '</ul>';
+                            }
+                        }
                         popup.innerHTML = content;
 
                         // Position popup near the cell
@@ -326,7 +346,7 @@
     puts("<td class=\"out-of-range\"></td>");
 }
 
-void html::cell(year_month_day ymd, const fm::commits &commits) {
+void html::cell(year_month_day ymd, bool hide_repo_names, const fm::commits &commits) {
     const char *color_class;
     if (commits.count() == 0) {
         color_class = "zero-commits";
@@ -351,25 +371,41 @@
         static_cast<unsigned>(ymd.month()),
         static_cast<unsigned>(ymd.day()));
 
-    // Build a JSON array of commit summaries
-    // We have to iterate in reverse order to sort the summaries chronologically
-    std::string summaries_json = "[";
-    for (const auto &summary :  commits.summaries | std::views::reverse) {
-        // Escape quotes in JSON
-        size_t pos = summary.find('\"');
-        if (pos == std::string::npos) {
-            summaries_json += "\"" + summary + "\",";
-        } else {
-            std::string escaped = summary;
-            do {
-                escaped.replace(pos, 1, "\\\"");
-                pos += 2;
-            } while ((pos = escaped.find('\"', pos)) != std::string::npos);
-            summaries_json += "\"" + escaped + "\",";
+    // Build a JSON object of commit summaries
+    auto escape_json = [](std::string str) static {
+        size_t pos = str.find('\"');
+        if (pos == std::string::npos) return str;
+        std::string escaped = std::move(str);
+        do {
+            escaped.replace(pos, 1, "\\\"");
+            pos += 2;
+        } while ((pos = escaped.find('\"', pos)) != std::string::npos);
+        return escaped;
+    };
+    auto add_summaries = [escape_json](std::string &json, const std::vector<std::string> &summaries) {
+        // We have to iterate in reverse order to sort the summaries chronologically
+        for (const auto &summary :  summaries | std::views::reverse) {
+            json += "\"" + escape_json(summary) + "\",";
         }
+        json.pop_back();
+    };
+    std::string summaries_json;
+    if (hide_repo_names) {
+        summaries_json += '[';
+        for (const auto &summaries: commits.summaries | std::views::values) {
+            add_summaries(summaries_json, summaries);
+        }
+        summaries_json += ']';
+    } else {
+        summaries_json += '{';
+        for (const auto &[repo, summaries] : commits.summaries) {
+            summaries_json += "\"" + escape_json(repo) + "\":[";
+            add_summaries(summaries_json, summaries);
+            summaries_json += "],";
+        }
+        summaries_json.pop_back();
+        summaries_json += '}';
     }
-    summaries_json.pop_back();
-    summaries_json += "]";
 
     indent();
     printf("<td class=\"%s\" title=\"%s: %u %s\" data-date=\"%s\" data-summaries=\"%s\"></td>\n",

mercurial