diff options
| author | 2007-10-30 18:47:38 (JST) | |
|---|---|---|
| committer | 2007-10-30 21:38:34 (JST) | |
| commit | 0c8e184e9cbf4d3a1e907de9125f6d8210c169d6 (patch) | |
| tree | 2e82baf582b7ba0b34f498e1e7494800070067f9 | |
| parent | 10ac7ad1f30f914dc5ff36ba3651ef6dca11aaf7 (diff) | |
| download | cgit-0c8e184e9cbf4d3a1e907de9125f6d8210c169d6.zip cgit-0c8e184e9cbf4d3a1e907de9125f6d8210c169d6.tar.gz | |
Change the cgit layout
This modifies and hopefully improves the layout of all cgit pages:
* Remove the header from all pages and replace it with a sidebar;
most pages have sufficient width but many needs more height.
* Add a dropdown-box to switch between branches, using a one-liner
javascript to reload the current page in context of the selected branch.
* Include refs found below refs/archives in the sidebar, appearing as a
set of menuitems below a 'download' heading.
* Include the brand new cgit logo
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
| -rw-r--r-- | cgit.css | 149 | ||||
| -rw-r--r-- | cgit.h | 2 | ||||
| -rw-r--r-- | cgit.png | bin | 0 -> 3790 bytes | |||
| -rw-r--r-- | cgitrc | 9 | ||||
| -rw-r--r-- | shared.c | 31 | ||||
| -rw-r--r-- | ui-shared.c | 172 | ||||
| -rw-r--r-- | ui-summary.c | 65 |
7 files changed, 231 insertions, 197 deletions
| @@ -1,15 +1,16 @@ | |||
| 1 | body { | ||
| 2 | font-family: arial, sans-serif; | ||
| 3 | font-size: 11pt; | ||
| 4 | color: black; | ||
| 5 | background: white; | ||
| 6 | } | ||
| 7 | |||
| 8 | body, table { | 1 | body, table { |
| 9 | padding: 0em; | 2 | padding: 0em; |
| 10 | margin: 0em; | 3 | margin: 0em; |
| 11 | } | 4 | } |
| 12 | 5 | ||
| 6 | body { | ||
| 7 | font-family: sans; | ||
| 8 | font-size: 10pt; | ||
| 9 | color: #333; | ||
| 10 | background: white; | ||
| 11 | padding-left: 4px; | ||
| 12 | } | ||
| 13 | |||
| 13 | table { | 14 | table { |
| 14 | border-collapse: collapse; | 15 | border-collapse: collapse; |
| 15 | } | 16 | } |
| @@ -35,12 +36,13 @@ h4 { | |||
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | a { | 38 | a { |
| 38 | color: blue; | 39 | color: #600; |
| 39 | text-decoration: none; | 40 | text-decoration: none; |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | a:hover { | 43 | a:hover { |
| 43 | text-decoration: underline; | 44 | background-color: #ddd; |
| 45 | text-decoration: none; | ||
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | table.list { | 48 | table.list { |
| @@ -53,7 +55,7 @@ table.list tr { | |||
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | table.list tr:hover { | 57 | table.list tr:hover { |
| 56 | background: #eee; | 58 | background: #f8f8f8; |
| 57 | } | 59 | } |
| 58 | 60 | ||
| 59 | table.list tr.nohover:hover { | 61 | table.list tr.nohover:hover { |
| @@ -76,98 +78,78 @@ img { | |||
| 76 | border: none; | 78 | border: none; |
| 77 | } | 79 | } |
| 78 | 80 | ||
| 79 | table#layout { | 81 | div#sidebar { |
| 80 | width: 100%; | 82 | vertical-align: top; |
| 81 | border-collapse: collapse; | 83 | width: 162px; |
| 82 | margin: 0px; | 84 | padding: 0px 0px 0px 0px; |
| 83 | } | 85 | margin: 4px; |
| 84 | 86 | float: left; | |
| 85 | td#header, td#logo { | ||
| 86 | color: #666; | ||
| 87 | background-color: #ddd; | ||
| 88 | border-bottom: solid 1px #000; | ||
| 89 | } | ||
| 90 | |||
| 91 | td#header { | ||
| 92 | font-size: 150%; | ||
| 93 | font-weight: bold; | ||
| 94 | padding: 0.2em 0.5em; | ||
| 95 | vertical-align: text-bottom; | ||
| 96 | } | ||
| 97 | |||
| 98 | td#header a { | ||
| 99 | color: #666; | ||
| 100 | } | ||
| 101 | |||
| 102 | td#header a:hover { | ||
| 103 | text-decoration: underline; | ||
| 104 | } | 87 | } |
| 105 | 88 | ||
| 106 | td#logo { | 89 | div#logo { |
| 107 | text-align: right; | 90 | margin: 0px; |
| 108 | vertical-align: middle; | 91 | padding: 4px 0px 4px 0px; |
| 109 | padding-right: 0.5em; | 92 | text-align: center; |
| 93 | background-color: #ccc; | ||
| 94 | border-top: solid 1px #eee; | ||
| 95 | border-left: solid 1px #eee; | ||
| 96 | border-right: solid 1px #aaa; | ||
| 97 | border-bottom: solid 1px #aaa; | ||
| 110 | } | 98 | } |
| 111 | 99 | ||
| 112 | td#crumb, td#search { | 100 | div#sidebar div.infobox { |
| 113 | color: #ccc; | 101 | margin: 0px 0px 0pax 0px; |
| 114 | border-top: solid 3px #555; | 102 | padding: 0.5em; |
| 115 | background-color: #666; | 103 | text-align: left; |
| 116 | border-bottom: solid 1px #333; | 104 | background-color: #ccc; |
| 117 | padding: 2px 1em; | 105 | border-top: solid 1px #eee; |
| 106 | border-left: solid 1px #eee; | ||
| 107 | border-right: solid 1px #aaa; | ||
| 108 | border-bottom: solid 1px #aaa; | ||
| 118 | } | 109 | } |
| 119 | 110 | ||
| 120 | td#crumb { | 111 | div#sidebar div.infobox h1 { |
| 112 | font-size: 11pt; | ||
| 121 | font-weight: bold; | 113 | font-weight: bold; |
| 114 | margin: 0px; | ||
| 122 | } | 115 | } |
| 123 | 116 | ||
| 124 | td#crumb a { | 117 | div#sidebar div.infobox a.menu { |
| 125 | color: #ccc; | 118 | display: block; |
| 126 | background-color: #666; | ||
| 127 | padding: 0em 0.5em 0em 0.5em; | ||
| 128 | } | ||
| 129 | |||
| 130 | td#crumb a:hover { | ||
| 131 | color: #666; | ||
| 132 | background-color: #ccc; | 119 | background-color: #ccc; |
| 120 | padding: 0.1em 0.5em; | ||
| 133 | text-decoration: none; | 121 | text-decoration: none; |
| 134 | } | 122 | } |
| 135 | 123 | ||
| 136 | td#search { | 124 | div#sidebar div.infobox a.menu:hover { |
| 137 | text-align: right; | 125 | background-color: #bbb; |
| 138 | vertical-align: middle; | 126 | text-decoration: none; |
| 139 | padding-right: 0.5em; | ||
| 140 | } | ||
| 141 | |||
| 142 | td#search form { | ||
| 143 | margin: 0px; | ||
| 144 | padding: 0px; | ||
| 145 | } | 127 | } |
| 146 | 128 | ||
| 147 | td#search select { | 129 | div#sidebar div.infobox select { |
| 148 | font-size: 9pt; | 130 | width: 100%; |
| 131 | border: solid 1px #aaa; | ||
| 132 | background-color: #bbb; | ||
| 133 | margin: 2px 0px 0px 0px; | ||
| 149 | padding: 0px; | 134 | padding: 0px; |
| 150 | border: solid 1px #333; | ||
| 151 | color: #333; | ||
| 152 | background-color: #fff; | ||
| 153 | } | 135 | } |
| 154 | 136 | ||
| 155 | td#search input { | 137 | div#sidebar div.infobox input.txt { |
| 156 | font-size: 9pt; | 138 | width: 100%; |
| 157 | padding: 0px; | 139 | border: solid 1px #aaa; |
| 140 | background-color: #bbb; | ||
| 141 | margin: 2px 0px 0px 0px; | ||
| 142 | padding: 0; | ||
| 158 | } | 143 | } |
| 159 | 144 | ||
| 160 | td#search input.txt { | 145 | table#grid { |
| 161 | width: 8em; | 146 | margin: 0px; |
| 162 | border: solid 1px #333; | ||
| 163 | color: #333; | ||
| 164 | background-color: #fff; | ||
| 165 | } | 147 | } |
| 166 | 148 | ||
| 167 | td#search input.btn { | 149 | td#content { |
| 168 | border: solid 1px #333; | 150 | vertical-align: top; |
| 169 | color: #333; | 151 | padding: 1em 2em 1em 1em; |
| 170 | background-color: #ccc; | 152 | border: none; |
| 171 | } | 153 | } |
| 172 | 154 | ||
| 173 | div#summary { | 155 | div#summary { |
| @@ -187,10 +169,6 @@ table#downloads th { | |||
| 187 | background-color: #ccc; | 169 | background-color: #ccc; |
| 188 | } | 170 | } |
| 189 | 171 | ||
| 190 | td#content { | ||
| 191 | padding: 1em 0.5em; | ||
| 192 | } | ||
| 193 | |||
| 194 | div#blob { | 172 | div#blob { |
| 195 | border: solid 1px black; | 173 | border: solid 1px black; |
| 196 | } | 174 | } |
| @@ -284,7 +262,6 @@ div.diffstat-header { | |||
| 284 | 262 | ||
| 285 | table.diffstat { | 263 | table.diffstat { |
| 286 | border-collapse: collapse; | 264 | border-collapse: collapse; |
| 287 | width: 100%; | ||
| 288 | border: solid 1px #aaa; | 265 | border: solid 1px #aaa; |
| 289 | background-color: #eee; | 266 | background-color: #eee; |
| 290 | } | 267 | } |
| @@ -325,7 +302,7 @@ table.diffstat td.upd a { | |||
| 325 | } | 302 | } |
| 326 | 303 | ||
| 327 | table.diffstat td.graph { | 304 | table.diffstat td.graph { |
| 328 | width: 75%; | 305 | width: 500px; |
| 329 | vertical-align: middle; | 306 | vertical-align: middle; |
| 330 | } | 307 | } |
| 331 | 308 | ||
| @@ -181,6 +181,8 @@ extern int chk_non_negative(int result, char *msg); | |||
| 181 | 181 | ||
| 182 | extern int hextoint(char c); | 182 | extern int hextoint(char c); |
| 183 | extern char *trim_end(const char *str, char c); | 183 | extern char *trim_end(const char *str, char c); |
| 184 | extern char *strlpart(char *txt, int maxlen); | ||
| 185 | extern char *strrpart(char *txt, int maxlen); | ||
| 184 | 186 | ||
| 185 | extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); | 187 | extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); |
| 186 | extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, | 188 | extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, |
diff --git a/cgit.png b/cgit.png new file mode 100644 index 0000000..ee48197 --- /dev/null +++ b/cgit.png | |||
| Binary files differ | |||
| @@ -85,8 +85,13 @@ | |||
| 85 | #root-title=Git repository browser | 85 | #root-title=Git repository browser |
| 86 | 86 | ||
| 87 | 87 | ||
| 88 | ## If specified, the file at this path will be included as HTML in the index | 88 | ## If specified, the file at this path will be included as HTML in the |
| 89 | ## of repositories | 89 | ## sidebar on the repository index page |
| 90 | #index-info= | ||
| 91 | |||
| 92 | |||
| 93 | ## If specified, the file at this path will be included as HTML above | ||
| 94 | ## the repository index | ||
| 90 | #index-header= | 95 | #index-header= |
| 91 | 96 | ||
| 92 | 97 | ||
| @@ -303,6 +303,37 @@ char *trim_end(const char *str, char c) | |||
| 303 | return s; | 303 | return s; |
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | char *strlpart(char *txt, int maxlen) | ||
| 307 | { | ||
| 308 | char *result; | ||
| 309 | |||
| 310 | if (!txt) | ||
| 311 | return txt; | ||
| 312 | |||
| 313 | if (strlen(txt) <= maxlen) | ||
| 314 | return txt; | ||
| 315 | result = xmalloc(maxlen + 1); | ||
| 316 | memcpy(result, txt, maxlen - 3); | ||
| 317 | result[maxlen-1] = result[maxlen-2] = result[maxlen-3] = '.'; | ||
| 318 | result[maxlen] = '\0'; | ||
| 319 | return result; | ||
| 320 | } | ||
| 321 | |||
| 322 | char *strrpart(char *txt, int maxlen) | ||
| 323 | { | ||
| 324 | char *result; | ||
| 325 | |||
| 326 | if (!txt) | ||
| 327 | return txt; | ||
| 328 | |||
| 329 | if (strlen(txt) <= maxlen) | ||
| 330 | return txt; | ||
| 331 | result = xmalloc(maxlen + 1); | ||
| 332 | memcpy(result + 3, txt + strlen(txt) - maxlen + 4, maxlen - 3); | ||
| 333 | result[0] = result[1] = result[2] = '.'; | ||
| 334 | return result; | ||
| 335 | } | ||
| 336 | |||
| 306 | void cgit_add_ref(struct reflist *list, struct refinfo *ref) | 337 | void cgit_add_ref(struct reflist *list, struct refinfo *ref) |
| 307 | { | 338 | { |
| 308 | size_t size; | 339 | size_t size; |
diff --git a/ui-shared.c b/ui-shared.c index 1418010..1d66940 100644 --- a/ui-shared.c +++ b/ui-shared.c | |||
| @@ -362,77 +362,149 @@ void cgit_print_docstart(char *title, struct cacheitem *item) | |||
| 362 | 362 | ||
| 363 | void cgit_print_docend() | 363 | void cgit_print_docend() |
| 364 | { | 364 | { |
| 365 | html("</td></tr></table>"); | 365 | html("</td>\n</tr>\n<table>\n</body>\n</html>\n"); |
| 366 | html("</body>\n</html>\n"); | 366 | } |
| 367 | |||
| 368 | int print_branch_option(const char *refname, const unsigned char *sha1, | ||
| 369 | int flags, void *cb_data) | ||
| 370 | { | ||
| 371 | char *name = (char *)refname; | ||
| 372 | html_option(name, name, cgit_query_head); | ||
| 373 | return 0; | ||
| 374 | } | ||
| 375 | |||
| 376 | int print_archive_ref(const char *refname, const unsigned char *sha1, | ||
| 377 | int flags, void *cb_data) | ||
| 378 | { | ||
| 379 | struct tag *tag; | ||
| 380 | struct taginfo *info; | ||
| 381 | struct object *obj; | ||
| 382 | char buf[256], *url; | ||
| 383 | unsigned char fileid[20]; | ||
| 384 | int *header = (int *)cb_data; | ||
| 385 | |||
| 386 | if (prefixcmp(refname, "refs/archives")) | ||
| 387 | return 0; | ||
| 388 | strncpy(buf, refname+14, sizeof(buf)); | ||
| 389 | obj = parse_object(sha1); | ||
| 390 | if (!obj) | ||
| 391 | return 1; | ||
| 392 | if (obj->type == OBJ_TAG) { | ||
| 393 | tag = lookup_tag(sha1); | ||
| 394 | if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) | ||
| 395 | return 0; | ||
| 396 | hashcpy(fileid, tag->tagged->sha1); | ||
| 397 | } else if (obj->type != OBJ_BLOB) { | ||
| 398 | return 0; | ||
| 399 | } else { | ||
| 400 | hashcpy(fileid, sha1); | ||
| 401 | } | ||
| 402 | if (!*header) { | ||
| 403 | html("<p><h1>download</h1>"); | ||
| 404 | *header = 1; | ||
| 405 | } | ||
| 406 | url = cgit_pageurl(cgit_query_repo, "blob", | ||
| 407 | fmt("id=%s&path=%s", sha1_to_hex(fileid), | ||
| 408 | buf)); | ||
| 409 | html_link_open(url, NULL, "menu"); | ||
| 410 | html_txt(strlpart(buf, 20)); | ||
| 411 | html_link_close(); | ||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | void add_hidden_formfields(int incl_head, int incl_search) | ||
| 416 | { | ||
| 417 | if (!cgit_virtual_root) { | ||
| 418 | if (cgit_query_repo) | ||
| 419 | html_hidden("r", cgit_query_repo); | ||
| 420 | if (cgit_query_page) | ||
| 421 | html_hidden("p", cgit_query_page); | ||
| 422 | } | ||
| 423 | |||
| 424 | if (incl_head && strcmp(cgit_query_head, cgit_repo->defbranch)) | ||
| 425 | html_hidden("h", cgit_query_head); | ||
| 426 | |||
| 427 | if (cgit_query_sha1) | ||
| 428 | html_hidden("id", cgit_query_sha1); | ||
| 429 | if (cgit_query_sha2) | ||
| 430 | html_hidden("id2", cgit_query_sha2); | ||
| 431 | |||
| 432 | if (incl_search) { | ||
| 433 | if (cgit_query_grep) | ||
| 434 | html_hidden("qt", cgit_query_grep); | ||
| 435 | if (cgit_query_search) | ||
| 436 | html_hidden("q", cgit_query_search); | ||
| 437 | } | ||
| 367 | } | 438 | } |
| 368 | 439 | ||
| 369 | void cgit_print_pageheader(char *title, int show_search) | 440 | void cgit_print_pageheader(char *title, int show_search) |
| 370 | { | 441 | { |
| 371 | html("<table id='layout'>"); | 442 | static const char *default_info = "This is cgit, a fast webinterface for git repositories"; |
| 372 | html("<tr><td id='header'><a href='"); | 443 | int header = 0; |
| 373 | html_attr(cgit_rooturl()); | 444 | |
| 374 | html("'>"); | 445 | html("<div id='sidebar'>\n"); |
| 375 | html_txt(cgit_root_title); | ||
| 376 | html("</a></td><td id='logo'>"); | ||
| 377 | html("<a href='"); | 446 | html("<a href='"); |
| 378 | html_attr(cgit_logo_link); | 447 | html_attr(cgit_rooturl()); |
| 379 | htmlf("'><img src='%s' alt='logo'/></a>", cgit_logo); | 448 | htmlf("'><div id='logo'><img src='%s' alt='cgit'/></div></a>\n", |
| 380 | html("</td></tr>"); | 449 | cgit_logo); |
| 381 | html("<tr><td id='crumb'>"); | 450 | html("<div class='infobox'>"); |
| 382 | if (cgit_query_repo) { | 451 | if (cgit_query_repo) { |
| 383 | html_txt(cgit_repo->name); | 452 | html("<h1>"); |
| 384 | html(" ("); | 453 | html_txt(strrpart(cgit_repo->name, 20)); |
| 385 | html_txt(cgit_query_head); | 454 | html("</h1>\n"); |
| 386 | html(") : "); | 455 | html_txt(cgit_repo->desc); |
| 387 | reporevlink(NULL, "summary", NULL, NULL, cgit_query_head, | 456 | if (cgit_repo->owner) { |
| 457 | html("<p>\n<h1>owner</h1>\n"); | ||
| 458 | html_txt(cgit_repo->owner); | ||
| 459 | } | ||
| 460 | html("<p>\n<h1>navigate</h1>\n"); | ||
| 461 | reporevlink(NULL, "summary", NULL, "menu", cgit_query_head, | ||
| 388 | NULL, NULL); | 462 | NULL, NULL); |
| 389 | html(" "); | 463 | cgit_log_link("log", NULL, "menu", cgit_query_head, |
| 390 | cgit_log_link("log", NULL, NULL, cgit_query_head, | ||
| 391 | cgit_query_sha1, cgit_query_path, 0); | 464 | cgit_query_sha1, cgit_query_path, 0); |
| 392 | html(" "); | 465 | cgit_tree_link("tree", NULL, "menu", cgit_query_head, |
| 393 | cgit_tree_link("tree", NULL, NULL, cgit_query_head, | ||
| 394 | cgit_query_sha1, NULL); | 466 | cgit_query_sha1, NULL); |
| 395 | html(" "); | 467 | cgit_commit_link("commit", NULL, "menu", cgit_query_head, |
| 396 | cgit_commit_link("commit", NULL, NULL, cgit_query_head, | ||
| 397 | cgit_query_sha1); | 468 | cgit_query_sha1); |
| 398 | html(" "); | 469 | cgit_diff_link("diff", NULL, "menu", cgit_query_head, |
| 399 | cgit_diff_link("diff", NULL, NULL, cgit_query_head, | ||
| 400 | cgit_query_sha1, cgit_query_sha2, | 470 | cgit_query_sha1, cgit_query_sha2, |
| 401 | cgit_query_path); | 471 | cgit_query_path); |
| 402 | } else { | 472 | |
| 403 | html_txt("Index of repositories"); | 473 | for_each_ref(print_archive_ref, &header); |
| 404 | } | 474 | |
| 405 | html("</td>"); | 475 | html("<p>\n<h1>branch</h1>\n"); |
| 406 | html("<td id='search'>"); | 476 | html("<form method='get' action=''>\n"); |
| 407 | if (show_search) { | 477 | add_hidden_formfields(0, 1); |
| 478 | html("<select name='h' onchange='this.form.submit();'>\n"); | ||
| 479 | for_each_branch_ref(print_branch_option, cgit_query_head); | ||
| 480 | html("</select>\n"); | ||
| 481 | html("</form>\n"); | ||
| 482 | |||
| 483 | html("<p>\n<h1>search</h1>\n"); | ||
| 408 | html("<form method='get' action='"); | 484 | html("<form method='get' action='"); |
| 409 | html_attr(cgit_currurl()); | 485 | ht |
