srctree

Gregory Mullen parent 347461a9 77861d6c
add readme to repo face sheet, make it pretty

src/endpoints/repos.zig added: 153, removed: 69, total 84
@@ -1,6 +1,7 @@
const std = @import("std");
 
const Allocator = std.mem.Allocator;
const aPrint = std.fmt.allocPrint;
 
const Endpoint = @import("../endpoint.zig");
const Context = @import("../context.zig");
@@ -106,7 +107,7 @@ fn htmlRepoBlock(a: Allocator, pre_dom: *DOM, name: []const u8, repo: git.Repo)
var dom = pre_dom.open(HTML.repo());
dom = dom.open(HTML.element("name", name, null));
dom.dupe(HTML.anch(name, &[_]HTML.Attribute{
.{ .key = "href", .value = try std.fmt.allocPrint(a, "/repo/{s}", .{name}) },
.{ .key = "href", .value = try aPrint(a, "/repo/{s}", .{name}) },
}));
dom = dom.close();
dom = dom.open(HTML.element("desc", null, null));
@@ -132,7 +133,7 @@ fn htmlRepoBlock(a: Allocator, pre_dom: *DOM, name: []const u8, repo: git.Repo)
if (repo.commit(a)) |cmt| {
defer cmt.raze(a);
const committer = cmt.committer;
const updated_str = try std.fmt.allocPrint(
const updated_str = try aPrint(
a,
"updated about {}",
.{Humanize.unix(committer.timestamp)},
@@ -218,7 +219,7 @@ fn treeBlob(r: *Response, uri: *UriIter) Error!void {
_ = uri.next();
 
var cwd = std.fs.cwd();
var filename = try std.fmt.allocPrint(r.alloc, "./repos/{s}", .{rd.name});
var filename = try aPrint(r.alloc, "./repos/{s}", .{rd.name});
var dir = cwd.openDir(filename, .{}) catch return error.Unknown;
var repo = git.Repo.init(dir) catch return error.Unknown;
repo.loadData(r.alloc) catch return error.Unknown;
@@ -287,7 +288,7 @@ fn blob(r: *Response, uri: *UriIter, repo: *git.Repo, pfiles: git.Tree) Error!vo
 
dom = dom.close();
var data = dom.done();
const filestr = try std.fmt.allocPrint(
const filestr = try aPrint(
r.alloc,
"{pretty}",
.{HTML.div(data, &HTML.Attr.class("code-block"))},
@@ -312,6 +313,30 @@ fn mkTree(a: Allocator, repo: git.Repo, uri: *UriIter, pfiles: git.Tree) !git.Tr
return files;
}
 
fn htmlReadme(a: Allocator, readme: []const u8) ![]HTML.E {
var dom = DOM.new(a);
 
dom = dom.open(HTML.element("readme", null, null));
dom.push(HTML.element("intro", "README.md", null));
dom = dom.open(HTML.element("code", null, null));
var litr = std.mem.split(u8, readme, "\n");
while (litr.next()) |dirty| {
var clean = try a.alloc(u8, dirty.len * 2);
clean = Bleach.sanitize(dirty, clean, .{}) catch return error.Unknown;
dom.push(HTML.element("ln", clean, null));
}
dom = dom.close();
dom = dom.close();
 
return dom.done();
}
 
fn isReadme(name: []const u8) bool {
if (name.len == 0) return false;
if (std.mem.eql(u8, name, "README.md")) return true;
return false;
}
 
fn tree(r: *Response, uri: *UriIter, repo: *git.Repo, files: *git.Tree) Error!void {
var tmpl = Template.find("repo.html");
tmpl.init(r.alloc);
@@ -323,13 +348,6 @@ fn tree(r: *Response, uri: *UriIter, repo: *git.Repo, files: *git.Tree) Error!vo
} else "unknown";
tmpl.addVar("branch.default", head) catch return error.Unknown;
 
var a_refs = try r.alloc.alloc([]const u8, repo.refs.len);
for (a_refs, repo.refs) |*dst, src| {
dst.* = src.branch.name;
}
var str_refs = try std.mem.join(r.alloc, "\n", a_refs);
tmpl.addVar("branches", str_refs) catch return error.Unknown;
 
const rd = RouteData.make(uri) orelse return error.Unrouteable;
uri.reset();
_ = uri.next();
@@ -343,24 +361,30 @@ fn tree(r: *Response, uri: *UriIter, repo: *git.Repo, files: *git.Tree) Error!vo
//}
 
var dom = DOM.new(r.alloc);
var current: git.Commit = repo.commit(r.alloc) catch return error.Unknown;
dom.pushSlice(try htmlCommit(r.alloc, current, rd.name, true));
dom = dom.open(HTML.element("repo", null, &HTML.Attr.class("landing")));
 
var commitblob = dom.done();
const commitstr = try std.fmt.allocPrint(r.alloc, "{}", .{HTML.divAttr(
commitblob,
&HTML.Attr.class("treecommit"),
)});
tmpl.addVar("commit", commitstr) catch return error.Unknown;
dom = dom.open(HTML.element("intro", null, null));
dom.push(HTML.h3(rd.name, null));
const branches = try aPrint(r.alloc, "{} branches", .{repo.refs.len});
dom.push(HTML.span(branches, null));
 
dom = DOM.new(r.alloc);
const c = repo.commit(r.alloc) catch return error.Unknown;
dom.push(HTML.span(c.message[0..@min(c.message.len, 58)], null));
const commit_time = try aPrint(r.alloc, " {}", .{Humanize.unix(c.committer.timestamp)});
dom = dom.open(HTML.span(null, &HTML.Attr.class("muted")));
const commit_href = try aPrint(r.alloc, "/repo/{s}/commit/{s}", .{ rd.name, c.sha[0..8] });
dom.push(HTML.text(commit_time));
dom.push(try HTML.aHrefText(r.alloc, c.sha[0..8], commit_href));
dom = dom.close();
dom = dom.close();
 
dom = dom.open(HTML.div(null, &HTML.Attr.class("treelist")));
if (file_uri_name.len > 0) {
const end = std.mem.lastIndexOf(u8, file_uri_name[0 .. file_uri_name.len - 1], "/") orelse 0;
dom = dom.open(HTML.element("tree", null, null));
const dd_href = &[_]HTML.Attribute{.{
.key = "href",
.value = try std.fmt.allocPrint(
.value = try aPrint(
r.alloc,
"/repo/{s}/tree/{s}",
.{ rd.name, file_uri_name[0..end] },
@@ -375,7 +399,7 @@ fn tree(r: *Response, uri: *UriIter, repo: *git.Repo, files: *git.Tree) Error!vo
for (files.objects) |obj| {
var href = &[_]HTML.Attribute{.{
.key = "href",
.value = try std.fmt.allocPrint(r.alloc, "/repo/{s}/{s}/{s}{s}{s}", .{
.value = try aPrint(r.alloc, "/repo/{s}/{s}/{s}{s}{s}", .{
rd.name,
if (obj.isFile()) "blob" else "tree",
file_uri_name,
@@ -394,20 +418,36 @@ fn tree(r: *Response, uri: *UriIter, repo: *git.Repo, files: *git.Tree) Error!vo
// I know... I KNOW!!!
for (changed) |ch| {
if (std.mem.eql(u8, ch.name, obj.name)) {
dom = dom.open(HTML.div(null, null));
dom.dupe(HTML.span(if (std.mem.indexOf(u8, ch.commit, "\n\n")) |i|
ch.commit[0..i]
else
ch.commit, null));
dom.dupe(HTML.span(try std.fmt.allocPrint(r.alloc, "{}", .{Humanize.unix(ch.timestamp)}), null));
dom.dupe(HTML.span(try aPrint(r.alloc, "{}", .{Humanize.unix(ch.timestamp)}), null));
dom = dom.close();
break;
}
}
dom = dom.close();
}
var data = dom.done();
_ = tmpl.addElements(r.alloc, "files", data) catch return error.Unknown;
var page = tmpl.buildFor(r.alloc, r) catch unreachable;
dom = dom.close();
 
dom = dom.close();
const data = dom.done();
_ = tmpl.addElements(r.alloc, "repo", data) catch return error.Unknown;
 
for (files.objects) |obj| {
if (isReadme(obj.name)) {
var resolve = repo.blob(r.alloc, &obj.hash) catch return error.Unknown;
var reader = resolve.reader();
const readme_txt = reader.readAllAlloc(r.alloc, 0xffffff) catch unreachable;
const readme = htmlReadme(r.alloc, readme_txt) catch unreachable;
_ = tmpl.addElementsFmt(r.alloc, "{pretty}", "readme", readme) catch return error.Unknown;
break;
}
}
 
var page = tmpl.buildFor(r.alloc, r) catch unreachable;
r.status = .ok;
r.start() catch return Error.Unknown;
r.send(page) catch return Error.Unknown;
 
src/template.zig added: 153, removed: 69, total 84
@@ -46,11 +46,12 @@ pub const Template = struct {
}
}
 
/// caller owns of the returned slice, freeing the data before the final use is undefined
pub fn addElements(self: *Template, a: Allocator, name: []const u8, els: []const HTML.Element) ![]const u8 {
return self.addElementsFmt(a, "{}", name, els);
}
 
// caller is responsable to free the returned slice *AFTER* the final use
/// caller owns of the returned slice, freeing the data before the final use is undefined
pub fn addElementsFmt(self: *Template, a: Allocator, comptime fmt: []const u8, name: []const u8, els: []const HTML.Element) ![]const u8 {
try self.expandVars();
var list = try a.alloc([]u8, els.len);
 
static/main.css added: 153, removed: 69, total 84
@@ -27,12 +27,21 @@ a {
}
}
 
h1,h2,h3 { margin: 0 }
 
.repo-btns {
display: block;
margin: 0 16px 16px;
text-align: right;
}
 
.muted {
color: #bbb;
font-family: 'Titillium Web', sans-serif;
font-size: 80%;
margin: 6px 0 0;
}
 
body { margin: 0 auto; }
 
header {
@@ -115,13 +124,36 @@ repos {
justify-content: flex-start;
margin: auto;
text-align: left;
repo {
min-width: 320px;
max-width: 480px;
width: 48%;
margin: 0 auto 10px 0.5%;
}
}
 
 
repo {
min-width: 320px;
max-width: 480px;
width: 48%;
margin: 0 auto 10px 0.5%;
display: block;
&.landing {
border-radius: 4px 4px 0 0;
border: 1px solid #808080;
intro {
 
span:first-child{
font-family: 'Titillium Web', sans-serif;
font-size: 120%;
}
border-radius: 4px 4px 0 0;
padding: 10px;
background: #333;
display: flex;
justify-content: space-between;
align-items: baseline;
text-align: left;
}
 
}
 
name {
font-family: 'Titillium Web', sans-serif;
@@ -164,6 +196,49 @@ repo {
}
}
 
readme {
border: 1px solid gray;
display: block;
margin: 2rem 0 10rem;
border-radius: 4px 4px 0 0;
intro {
border-radius: 4px 4px 0 0;
padding: 10px;
background: #333;
display: flex;
justify-content: space-between;
align-items: baseline;
text-align: left;
}
}
 
.treelist {
padding: 0 8px 8px;
font-family: 'Ubuntu Mono', sans-serif;
tree, file {
border-top: 1px solid gray;
margin: auto;
padding: 4px;
text-align: left;
display: flex;
justify-content: flex-start;
> a {
min-width: 25%;
display: inline-block;
}
&:first-child { border-top: 0px solid gray; }
div {
display: flex;
justify-content: space-between;
flex-grow: 1;
}
}
> tree > a::before { content: "📁"; padding-right: 8px;}
> file > a::before { content: "📄"; padding-right: 8px;}
}
 
 
 
search {
font-family: 'Titillium Web', sans-serif;
background: #333;
@@ -203,30 +278,6 @@ li {
display: block;
list-style: none;
}
 
.treelist {
background: #333;
padding: 10px;
font-family: 'Ubuntu Mono', sans-serif;
tree, file {
border: 2px solid gray;
border-top: 0px;
margin: auto;
padding: 4px;
text-align: left;
width: 98%;
display: flex;
justify-content: space-between;
> a {
min-width: 25%;
display: inline-block;
}
&:first-child { border-top: 2px solid gray; }
}
> tree > a::before { content: "📁"; padding-right: 8px;}
> file > a::before { content: "📄"; padding-right: 8px;}
}
 
commit {
display: block;
text-align: left;
 
templates/repo.html added: 153, removed: 69, total 84
@@ -7,15 +7,7 @@
<body>
<!-- _body_header.html -->
<content>
<!-- commit -->
 
<div class="treelist">
<!-- files -->
</div>
 
<b><!-- branch.default --></b>
<p>branches</p>
<!-- branches -->
</content>
<!-- repo -->
<!-- readme -->
</body>
</html>