summary  | 
shortlog  | 
log  | 
commit  | 
commitdiff  | 
tree 
raw  | 
patch  | 
inline  | side by side (from parent 1: 
071afd4 )
 
 
• Better markup 
• Went from [search, page_nav] to [header[page_nav, search]] 
• Less float, more flex 
• Normal font size rather than small, removed border around everything. 
 
More invasive stuff coming shortly. 
 ## functions printing HTML: header, footer, error page
 
 sub get_page_title {
 ## functions printing HTML: header, footer, error page
 
 sub get_page_title {
-       my $title = to_utf8($site_name);
-
+       # Formats:
+       # SITE_NAME
+       # SITE_NAME - projects in FILTER
+       # PROJECT - SITE_NAME
+       # PROJECT ACTION - SITE_NAME
+       # FILENAME - PROJECT ACTION - SITE_NAME
+       my $title;
        unless (defined $project) {
        unless (defined $project) {
+               $title = to_utf8($site_name);
                if (defined $project_filter) {
                        $title .= " - projects in '" . esc_path($project_filter) . "'";
                }
                return $title;
        }
                if (defined $project_filter) {
                        $title .= " - projects in '" . esc_path($project_filter) . "'";
                }
                return $title;
        }
-       $title .= " - " . to_utf8($project);
-
-       return $title unless (defined $action);
-       $title .= "/$action"; # $action is US-ASCII (7bit ASCII)
+       $title = to_utf8($project);
-       return $title unless (defined $file_name);
-       $title .= " - " . esc_path($file_name);
-       if ($action eq "tree" && $file_name !~ m|/$|) {
-               $title .= "/";
+       if (defined $action) {
+               $title .= " $action"; # $action is US-ASCII (7bit ASCII)
+               if (defined $file_name) {
+                       $title = " - " . $title;
+                       if ($action eq "tree" && $file_name !~ m|/$|) {
+                               $title = "/" . $title;
+                       }
+                       $title = esc_path($file_name) . $title;
+               }
+       $title .= " - " . to_utf8($site_name);
-sub get_content_type_html {
-       # require explicit support from the UA if we are to send the page as
-       # 'application/xhtml+xml', otherwise send it as plain old 'text/html'.
-       # we have to do this because MSIE sometimes globs '*/*', pretending to
-       # support xhtml+xml but choking when it gets what it asked for.
-       if (defined $cgi->http('HTTP_ACCEPT') &&
-           $cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ &&
-           $cgi->Accept('application/xhtml+xml') != 0) {
-               return 'application/xhtml+xml';
-       } else {
-               return 'text/html';
-       }
 
        # print out each stylesheet that exist, providing backwards capability
        # for those people who defined $stylesheet in a config file
        if (defined $stylesheet) {
        # print out each stylesheet that exist, providing backwards capability
        # for those people who defined $stylesheet in a config file
        if (defined $stylesheet) {
-               print '<link rel="stylesheet" type="text/css"  href="'.esc_url($stylesheet).'"/>'."\n";
+               print '<link rel="stylesheet" href="'.esc_url($stylesheet).'"/>'."\n";
        } else {
                foreach my $stylesheet (@stylesheets) {
                        next unless $stylesheet;
        } else {
                foreach my $stylesheet (@stylesheets) {
                        next unless $stylesheet;
-                       print '<link rel="stylesheet" type="text/css"  href="'.esc_url($stylesheet).'"/>'."\n";
+                       print '<link rel="stylesheet" href="'.esc_url($stylesheet).'"/>'."\n";
                }
        }
        print_feed_meta()
                if ($status eq '200 OK');
        if (defined $favicon) {
                }
        }
        print_feed_meta()
                if ($status eq '200 OK');
        if (defined $favicon) {
-               print qq(<link rel="shortcut icon" href=").esc_url($favicon).qq(" type="image/png"  />\n);
+               print qq(<link rel="icon" href=").esc_url($favicon).qq(" />\n);
 
        if ($use_pathinfo) {
                $action .= "/".esc_url($project);
        }
        if ($use_pathinfo) {
                $action .= "/".esc_url($project);
        }
-       print $cgi->start_form(-method => "get", -action => $action) .
-             "<div class=\"search\">\n" .
+       print $cgi->start_form(-method => "get", -action => $action, -role => "search") .
              (!$use_pathinfo &&
              $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") .
              $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" .
              (!$use_pathinfo &&
              $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") .
              $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" .
 
              $cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
                             -checked => $search_use_regexp) .
              "</span>" .
              $cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
                             -checked => $search_use_regexp) .
              "</span>" .
              $cgi->end_form() . "\n";
 }
 
              $cgi->end_form() . "\n";
 }
 
 
        my %opts = @_;
 
        my $title = get_page_title();
        my %opts = @_;
 
        my $title = get_page_title();
-       my $content_type = get_content_type_html();
-       print $cgi->header(-type=>$content_type, -charset => 'utf-8',
+       # I wanted to switch to text/html, but it uses nested <a> in a couple of places (e.g. log refs are links inside the commit summary link), which is invalid but works in the XML syntax. Pity.
+       # (Various other invalid HTML is produced that HTML would have fixed but XHTML allows to be broken, like table > tr, lacking tbody.)
+       # TODO: reduce the doctype to <!DOCTYPE html>, but that takes replacing entities like ⋅ with ⋅.
+       print $cgi->header(-type => 'application/xhtml+xml', -charset => 'utf-8',
                           -status=> $status, -expires => $expires)
                unless ($opts{'-no_http_header'});
                           -status=> $status, -expires => $expires)
                unless ($opts{'-no_http_header'});
-       my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
        print <<EOF;
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
        print <<EOF;
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
-<!-- git web interface version $version, (C) 2005-2006, Kay Sievers <kay.sievers\@vrfy.org>, Christian Gierke -->
-<!-- git core binaries version $git_version -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-AU" lang="en-AU">
-<meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
-<meta name="generator" content="gitweb/$version git/$git_version$mod_perl_version"/>
 <meta name="robots" content="index, nofollow"/>
 <title>$title</title>
 EOF
        # the stylesheet, favicon etc urls won't work correctly with path_info
        # unless we set the appropriate base URL
        if ($ENV{'PATH_INFO'}) {
 <meta name="robots" content="index, nofollow"/>
 <title>$title</title>
 EOF
        # the stylesheet, favicon etc urls won't work correctly with path_info
        # unless we set the appropriate base URL
        if ($ENV{'PATH_INFO'}) {
-               print "<base href=\"".esc_url($base_url)."\"  />\n";
+               print "<base href=\"".esc_url($base_url)."\"/>\n";
        }
        print_header_links($status);
 
        }
        print_header_links($status);
 
 
                print to_utf8($site_html_head_string);
        }
 
                print to_utf8($site_html_head_string);
        }
 
-       print "</head>\n" .
-             "<body>\n";
-
        if (defined $site_header && -f $site_header) {
                insert_file($site_header);
        }
 
        if (defined $site_header && -f $site_header) {
                insert_file($site_header);
        }
 
-       print "<div  class=\"page_header\">\n";
+       print "</head>\n<body>\n<header  class=\"page_header\">\n";
        if (defined $logo) {
                print $cgi->a({-href => esc_url($logo_url),
                               -title => $logo_label},
        if (defined $logo) {
                print $cgi->a({-href => esc_url($logo_url),
                               -title => $logo_label},
 
                                         -class => "logo"}));
        }
        print_nav_breadcrumbs(%opts);
                                         -class => "logo"}));
        }
        print_nav_breadcrumbs(%opts);
+       print "</header>\n";
+
+       print "<nav class=\"page_subhead\">\n";
+}
+sub git_end_subhead_html {
        my $have_search = gitweb_check_feature('search');
        if (defined $project && $have_search) {
                print_search_form();
        }
        my $have_search = gitweb_check_feature('search');
        if (defined $project && $have_search) {
                print_search_form();
        }
 }
 
 sub git_footer_html {
        my $feed_class = 'rss_logo';
 
 }
 
 sub git_footer_html {
        my $feed_class = 'rss_logo';
 
-       print "<div  class=\"page_footer\">\n";
+       print "<footer  class=\"page_footer\">\n";
        if (defined $project) {
                my $descr = git_get_project_description($project);
                if (defined $descr) {
        if (defined $project) {
                my $descr = git_get_project_description($project);
                if (defined $descr) {
 
                                             project_filter => $project_filter),
                              -class => $feed_class}, "TXT") . "\n";
        }
                                             project_filter => $project_filter),
                              -class => $feed_class}, "TXT") . "\n";
        }
-       print "</div >\n"; # class="page_footer"
+       print "</footer >\n"; # class="page_footer"
 
        if (defined $t0 && gitweb_check_feature('timed')) {
                print "<div id=\"generating_info\">\n";
 
        if (defined $t0 && gitweb_check_feature('timed')) {
                print "<div id=\"generating_info\">\n";
 
                      $number_of_git_cmds.
                      '</span> git commands '.
                      " to generate.\n";
                      $number_of_git_cmds.
                      '</span> git commands '.
                      " to generate.\n";
-               print "</div>\n"; # class="page_footer" 
        }
 
        if (defined $site_footer && -f $site_footer) {
        }
 
        if (defined $site_footer && -f $site_footer) {
 
                503 => '503 Service Unavailable',
        );
        git_header_html($http_responses{$status}, undef, %opts);
                503 => '503 Service Unavailable',
        );
        git_header_html($http_responses{$status}, undef, %opts);
+       git_end_subhead_html();
        print <<EOF;
 <div class="page_body">
 <br /><br />
        print <<EOF;
 <div class="page_body">
 <br /><br />
 
 
 sub git_print_page_nav {
        my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
 
 sub git_print_page_nav {
        my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
-       $extra = '' if !defined $extra; # pager or formats
 
        my @navs = qw(summary shortlog log commit commitdiff tree);
        if ($suppress) {
 
        my @navs = qw(summary shortlog log commit commitdiff tree);
        if ($suppress) {
 
                 map { $_ eq $current ?
                       $_ : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_")
                 } @navs);
                 map { $_ eq $current ?
                       $_ : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_")
                 } @navs);
-       print "<br/>\n$extra<br/>\n" .
-             "</div>\n";
+       print "<br/>\n$extra" if defined $extra; # pager or formats
+       print "</div>\n";
+       git_end_subhead_html();
 }
 
 # returns a submenu for the navigation of the refs views (tags, heads,
 }
 
 # returns a submenu for the navigation of the refs views (tags, heads,
 
+       git_end_subhead_html();
        if (defined $home_text && -f $home_text) {
                print "<div class=\"index_include\">\n";
                insert_file($home_text);
        if (defined $home_text && -f $home_text) {
                print "<div class=\"index_include\">\n";
                insert_file($home_text);
 
                git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
                git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
        } else {
                git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
                git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
        } else {
-               print "<div class=\"page_nav\">\n" .
-                     "<br/><br/></div>\n" .
-                     "<div class=\"title\">".esc_html($hash)."</div>\n";
+               git_end_subhead_html();
+               print "<div class=\"title\">".esc_html($hash)."</div>\n";
        }
        git_print_page_path($file_name, "blob", $hash_base);
        print "<div class=\"page_body\">\n";
        }
        git_print_page_path($file_name, "blob", $hash_base);
        print "<div class=\"page_body\">\n";
 
                git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
        } else {
                undef $hash_base;
                git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
        } else {
                undef $hash_base;
-               print "<div class=\"page_nav\">\n";
-               print "<br/><br/></div>\n";
+               git_end_subhead_html();
                print "<div class=\"title\">".esc_html($hash)."</div>\n";
        }
        if (defined $file_name) {
                print "<div class=\"title\">".esc_html($hash)."</div>\n";
        }
        if (defined $file_name) {
 
                        git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
                        git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
                } else {
                        git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
                        git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
                } else {
-                       print "<div class=\"page_nav\"><br/>$formats_nav<br/></div>\n";
+                       print "<div class=\"page_nav\"><br/>$formats_nav</div>\n";
+                       git_end_subhead_html();
                        print "<div class=\"title\">".esc_html("$hash vs $hash_parent")."</div>\n";
                }
                if (defined $file_name) {
                        print "<div class=\"title\">".esc_html("$hash vs $hash_parent")."</div>\n";
                }
                if (defined $file_name) {
 
+html,
+body {
+       height: 100%;
+}
+
 body {
        font-family: sans-serif;
 body {
        font-family: sans-serif;
-       font-size: small;
-       border: solid #d9d8d1;
-       border-width: 1px;
-       margin: 10px;
        background-color: #ffffff;
        color: #000000;
        background-color: #ffffff;
        color: #000000;
+       display: flex;
+       flex-direction: column;
 
-div.page_header {
-       height: 25px;
-       padding: 8px;
+.page_header {
+       padding: 1rem;
        font-size: 150%;
        font-weight: bold;
        font-size: 150%;
        font-weight: bold;
-       background-color: #d9d8d1;
+       border-top: 0.25rem solid #f71;
+       background-color: #f716;
-div .page_header a:visited, a.header {
+.page_header a:visited, a.header {
-div .page_header a:hover {
+/* .page_header + nav.page_subhead now wraps .page_nav and the search form, which is reduced from <form><div class=search> to <form role=search>; and both it and .page_nav are optional; and page_nav comes first rather than last. */
+.page_subhead {
+       display: flex;
+       background: #eee;
+       margin-bottom: 1em;
+}
+
 }
 
 div.page_nav a:visited {
 }
 
 div.page_nav a:visited {
 
        border-width: 0px 0px 1px;
 }
 
        border-width: 0px 0px 1px;
 }
 
-div.page_footer {
-       height: 22px;
+footer {
+       margin-top: auto;
+       display: flex;
        padding: 4px 8px;
        background-color: #d9d8d1;
        padding: 4px 8px;
        background-color: #d9d8d1;
+       justify-content: flex-end;
        float: left;
        color: #555555;
        font-style: italic;
        float: left;
        color: #555555;
        font-style: italic;
 
-div.search {
-       font-size: 100%;
-       font-weight: normal;
-       margin: 4px 8px;
-       float: right;
-       top: 56px;
-       right: 12px
+.page_subhead [role=search] {
+       margin: 0.5rem 1rem 0.5rem auto;
 
        border: 1px solid;
        border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
        color: #ffffff;
        border: 1px solid;
        border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
        color: #ffffff;