Fri, 31 Jan 2025 22:11:04 +0100
finish MVP
/* Copyright 2025 Mike Becker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "html.h" #include <cstdio> namespace html { static unsigned indentation; static const char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; static void indent(int change = 0) { indentation += change; fwrite(tabs, 1, indentation, stdout); } static std::string encode(const std::string &data) { std::string buffer; buffer.reserve(data.size()+16); for (const char &pos: data) { switch (pos) { case '&': buffer.append("&"); break; case '\"': buffer.append("""); break; case '\'': buffer.append("'"); break; case '<': buffer.append("<"); break; case '>': buffer.append(">"); break; default: buffer.append(&pos, 1); break; } } return buffer; } } void html::open() { puts( R"(<html> <head> <style> table.heatmap { table-layout: fixed; border-collapse: collapse; font-family: sans-serif; } table.heatmap td, table.heatmap th { text-align: center; border: solid 1px lightgray; height: 1.5em; } table.heatmap td { border: solid 1px lightgray; width: 1.5em; height: 1.5em; } table.heatmap td.out-of-range { background-color: gray; } </style> </head> <body>)"); indentation = 2; } void html::close() { puts("\t</body>\n</html>"); } void html::h1(const std::string& heading) { indent(); printf("<h1>%s</h1>\n", encode(heading).c_str()); } void html::h2(const std::string& heading) { indent(); printf("<h2>%s</h2>\n", encode(heading).c_str()); } void html::table_begin() { indent(); puts("<table class=\"heatmap\">"); indent(1); puts("<tr>"); indent(1); puts("<th></th>"); static constexpr const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; static constexpr int colspans[] = {5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 5}; for (unsigned i = 0 ; i < 12 ; i++) { indent(); printf("<th scope=\"col\" colspan=\"%d\">%s</th>\n", colspans[i], months[i]); } indent(-1); puts("</tr>"); } void html::table_end() { indentation--; indent(); puts("</table>"); } void html::row_begin(unsigned int row) { static constexpr const char* weekdays[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; indent(); puts("<tr>"); indent(1); printf("<th scope=\"row\">%s</th>\n", weekdays[row]); } void html::row_end() { indent(-1); puts("</tr>"); } void html::cell_out_of_range() { indent(); puts("<td class=\"out-of-range\"></td>"); } void html::cell(unsigned commits) { indent(); // TODO: use nice coloring and tooltips instead of printing the commits printf("<td>%u</td>\n", commits); }